from fastapi import FastAPI, HTTPException, Depends, status, UploadFile, File, Form
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse, StreamingResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
from typing import List, Tuple, Optional, Dict, Any
from pathlib import Path
from urllib.parse import unquote
import hashlib
import secrets
import time
import json
import os
import uvicorn
import pandas as pd
import io
import openpyxl
import re
import sqlite3
from functools import wraps
from datetime import datetime, timedelta
import asyncio
from concurrent.futures import ThreadPoolExecutor
import functools

import cookie_manager
from db_manager import db_manager
from file_log_collector import setup_file_logging, get_file_log_collector
from loguru import logger

# 条件导入AI回复引擎，避免缺少openai依赖时启动失败
try:
    from ai_reply_engine import ai_reply_engine
except ImportError as e:
    logger.warning(f"AI回复引擎导入失败，相关功能将不可用: {e}")
    ai_reply_engine = None
from utils.qr_login import qr_login_manager
from utils.xianyu_utils import trans_cookies
from utils.image_utils import image_manager

# ================== 缓存机制 ==================

class SimpleCache:
    """简单的内存缓存实现"""
    def __init__(self):
        self._cache = {}
        self._timestamps = {}
        
    def get(self, key: str, default_ttl: int = 300):
        """获取缓存值，默认TTL为5分钟"""
        if key not in self._cache:
            return None
            
        # 检查是否过期
        timestamp = self._timestamps.get(key, 0)
        if time.time() - timestamp > default_ttl:
            self.delete(key)
            return None
            
        return self._cache[key]
    
    def set(self, key: str, value, ttl: int = 300):
        """设置缓存值"""
        self._cache[key] = value
        self._timestamps[key] = time.time()
        
        # 简单的清理机制：当缓存项超过1000个时，清理过期项
        if len(self._cache) > 1000:
            self._cleanup_expired()
    
    def delete(self, key: str):
        """删除缓存项"""
        self._cache.pop(key, None)
        self._timestamps.pop(key, None)
    
    def clear(self):
        """清空所有缓存"""
        self._cache.clear()
        self._timestamps.clear()
    
    def clear_by_prefix(self, prefix: str):
        """根据前缀清理缓存项"""
        keys_to_delete = []
        for key in self._cache.keys():
            if key.startswith(prefix):
                keys_to_delete.append(key)
        
        for key in keys_to_delete:
            self.delete(key)
    
    def _cleanup_expired(self):
        """清理过期的缓存项"""
        current_time = time.time()
        expired_keys = []
        
        for key, timestamp in self._timestamps.items():
            if current_time - timestamp > 600:  # 10分钟过期
                expired_keys.append(key)
        
        for key in expired_keys:
            self.delete(key)

# 全局缓存实例
app_cache = SimpleCache()

def cache_result(ttl: int = 300, key_prefix: str = ""):
    """缓存装饰器，支持同步和异步函数"""
    def decorator(func):
        @wraps(func)
        async def async_wrapper(*args, **kwargs):
            # 生成缓存键
            cache_key = f"{key_prefix}:{func.__name__}:{hash(str(args) + str(sorted(kwargs.items())))}"
            
            # 尝试从缓存获取
            cached_result = app_cache.get(cache_key, ttl)
            if cached_result is not None:
                logger.debug(f"缓存命中: {cache_key}")
                return cached_result
            
            # 执行函数并缓存结果
            if asyncio.iscoroutinefunction(func):
                result = await func(*args, **kwargs)
            else:
                result = func(*args, **kwargs)
            app_cache.set(cache_key, result, ttl)
            logger.debug(f"缓存设置: {cache_key}")
            
            return result
            
        @wraps(func)
        def sync_wrapper(*args, **kwargs):
            # 生成缓存键
            cache_key = f"{key_prefix}:{func.__name__}:{hash(str(args) + str(sorted(kwargs.items())))}"
            
            # 尝试从缓存获取
            cached_result = app_cache.get(cache_key, ttl)
            if cached_result is not None:
                logger.debug(f"缓存命中: {cache_key}")
                return cached_result
            
            # 执行函数并缓存结果
            result = func(*args, **kwargs)
            app_cache.set(cache_key, result, ttl)
            logger.debug(f"缓存设置: {cache_key}")
            
            return result
            
        # 根据函数类型返回对应的wrapper
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    return decorator

def invalidate_user_cache(user_id: int):
    """清除指定用户的相关缓存"""
    # 这里可以实现更精确的缓存失效逻辑
    # 目前简单实现：清除包含用户ID的所有缓存项
    keys_to_delete = []
    for key in app_cache._cache.keys():
        if f"user_{user_id}" in key:
            keys_to_delete.append(key)
    
    for key in keys_to_delete:
        app_cache.delete(key)

# 关键字文件路径
KEYWORDS_FILE = Path(__file__).parent / "回复关键字.txt"

# 简单的用户认证配置
ADMIN_USERNAME = "admin"
DEFAULT_ADMIN_PASSWORD = "admin123"  # 系统初始化时的默认密码
SESSION_TOKENS = {}  # 存储会话token: {token: {'user_id': int, 'username': str, 'timestamp': float}}
TOKEN_EXPIRE_TIME = 24 * 60 * 60  # token过期时间：24小时

# HTTP Bearer认证
security = HTTPBearer(auto_error=False)

# 不再需要单独的密码初始化，由数据库初始化时处理

# 创建线程池执行器，用于处理CPU密集型任务
thread_pool = ThreadPoolExecutor(max_workers=4)

def run_in_thread(func):
    """装饰器：在线程池中运行CPU密集型函数"""
    @functools.wraps(func)
    async def wrapper(*args, **kwargs):
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(thread_pool, func, *args, **kwargs)
    return wrapper

def run_sync_in_thread(func):
    """装饰器：将同步函数包装为异步函数在线程池中运行"""
    @functools.wraps(func)
    def sync_wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    
    @functools.wraps(func)
    async def async_wrapper(*args, **kwargs):
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(thread_pool, sync_wrapper, *args, **kwargs)
    
    return async_wrapper

def load_keywords() -> List[Tuple[str, str]]:
    """读取关键字→回复映射表

    文件格式支持：
        关键字<空格/制表符/冒号>回复内容
    忽略空行和以 # 开头的注释行
    """
    mapping: List[Tuple[str, str]] = []
    if not KEYWORDS_FILE.exists():
        return mapping

    with KEYWORDS_FILE.open('r', encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith('#'):
                continue
            # 尝试用\t、空格、冒号分隔
            if '\t' in line:
                key, reply = line.split('\t', 1)
            elif ' ' in line:
                key, reply = line.split(' ', 1)
            elif ':' in line:
                key, reply = line.split(':', 1)
            else:
                # 无法解析的行，跳过
                continue
            mapping.append((key.strip(), reply.strip()))
    return mapping


KEYWORDS_MAPPING = load_keywords()


# 认证相关模型
class LoginRequest(BaseModel):
    username: Optional[str] = None
    password: Optional[str] = None
    email: Optional[str] = None
    verification_code: Optional[str] = None


class LoginResponse(BaseModel):
    success: bool
    token: Optional[str] = None
    message: str
    user_id: Optional[int] = None
    username: Optional[str] = None
    is_admin: Optional[bool] = None


class ChangePasswordRequest(BaseModel):
    current_password: str
    new_password: str


class RegisterRequest(BaseModel):
    username: str
    email: str
    password: str
    verification_code: str


class RegisterResponse(BaseModel):
    success: bool
    message: str


class SendCodeRequest(BaseModel):
    email: str
    session_id: Optional[str] = None
    type: Optional[str] = 'register'  # 'register' 或 'login'


class SendCodeResponse(BaseModel):
    success: bool
    message: str


class CaptchaRequest(BaseModel):
    session_id: str


class CaptchaResponse(BaseModel):
    success: bool
    captcha_image: str
    session_id: str
    message: str


class VerifyCaptchaRequest(BaseModel):
    session_id: str
    captcha_code: str


class VerifyCaptchaResponse(BaseModel):
    success: bool
    message: str


def generate_token() -> str:
    """生成随机token"""
    return secrets.token_urlsafe(32)


def verify_token(credentials: Optional[HTTPAuthorizationCredentials] = Depends(security)) -> Optional[Dict[str, Any]]:
    """验证token并返回用户信息"""
    if not credentials:
        return None

    token = credentials.credentials
    if token not in SESSION_TOKENS:
        return None

    token_data = SESSION_TOKENS[token]

    # 检查token是否过期
    if time.time() - token_data['timestamp'] > TOKEN_EXPIRE_TIME:
        del SESSION_TOKENS[token]
        return None

    return token_data


def verify_admin_token(credentials: Optional[HTTPAuthorizationCredentials] = Depends(security)) -> Dict[str, Any]:
    """验证管理员token"""
    user_info = verify_token(credentials)
    if not user_info:
        raise HTTPException(status_code=401, detail="未授权访问")

    # 检查是否是管理员
    if user_info['username'] != ADMIN_USERNAME:
        raise HTTPException(status_code=403, detail="需要管理员权限")

    return user_info


def require_auth(user_info: Optional[Dict[str, Any]] = Depends(verify_token)):
    """需要认证的依赖，返回用户信息"""
    if not user_info:
        raise HTTPException(status_code=401, detail="未授权访问")
    return user_info


def get_current_user(user_info: Dict[str, Any] = Depends(require_auth)) -> Dict[str, Any]:
    """获取当前登录用户信息"""
    return user_info


def get_current_user_optional(user_info: Optional[Dict[str, Any]] = Depends(verify_token)) -> Optional[Dict[str, Any]]:
    """获取当前用户信息（可选，不强制要求登录）"""
    return user_info


def get_user_log_prefix(user_info: Dict[str, Any] = None) -> str:
    """获取用户日志前缀"""
    if user_info:
        # 兼容新旧字段名
        user_id = user_info.get('id', user_info.get('user_id'))
        return f"【{user_info['username']}#{user_id}】"
    return "【系统】"


def require_admin(current_user: Dict[str, Any] = Depends(get_current_user)) -> Dict[str, Any]:
    """要求管理员权限"""
    if current_user['username'] != 'admin':
        raise HTTPException(status_code=403, detail="需要管理员权限")
    return current_user


def require_permission(permission_name: str):
    """要求特定权限的装饰器工厂"""
    def permission_checker(current_user: Dict[str, Any] = Depends(get_current_user)) -> Dict[str, Any]:
        from db_manager import db_manager
        
        # 管理员拥有所有权限
        if current_user['username'] == 'admin':
            return current_user
        
        # 检查用户是否拥有指定权限
        user_permissions = db_manager.get_user_permissions(current_user['user_id'])
        if permission_name not in user_permissions:
            raise HTTPException(status_code=403, detail=f"需要 {permission_name} 权限")
        
        return current_user
    
    return permission_checker


def log_with_user(level: str, message: str, user_info: Dict[str, Any] = None):
    """带用户信息的日志记录"""
    prefix = get_user_log_prefix(user_info)
    full_message = f"{prefix} {message}"

    if level.lower() == 'info':
        logger.info(full_message)
    elif level.lower() == 'error':
        logger.error(full_message)
    elif level.lower() == 'warning':
        logger.warning(full_message)
    elif level.lower() == 'debug':
        logger.debug(full_message)
    else:
        logger.info(full_message)


def generate_keyword_data_from_excel(file_content: bytes, item_id: str) -> List[Dict[str, Any]]:
    """
    从Excel文件读取前两列数据，生成关键词回复列表
    仿照批量添加自动回复软件中的逻辑

    参数:
        file_content: Excel文件内容（字节）
        item_id: 商品ID字符串

    返回:
        包含关键词回复字典的列表（去重后）
    """
    try:
        # 从系统设置中获取门店识别成功后的引导话术
        from db_manager import db_manager
        store_guide_text = db_manager.get_system_setting('store_guide_text')
        if not store_guide_text:
            store_guide_text = "上述店铺是可用的，直接拍就行"  # 默认话术
        
        # 使用io.BytesIO从内存中的字节数据创建文件对象
        file_obj = io.BytesIO(file_content)
        
        # 加载工作簿和工作表
        workbook = openpyxl.load_workbook(file_obj)
        sheet = workbook.active

        # 使用字典存储关键词，避免重复
        keyword_dict = {}
        # 按城市分组存储门店
        city_stores = {}

        # 遍历行（跳过标题行）
        for row in sheet.iter_rows(min_row=2, max_col=2, values_only=True):
            store_name = row[0]
            city = row[1]
            
            # 跳过空行
            if not store_name or not city:
                continue
            
            store_name = str(store_name).strip()
            city = str(city).strip()

            # 从门店名称提取关键词（括号内的内容，移除'店'字）
            keyword_match = re.search(r'（(.+?)店）', store_name)
            if keyword_match:
                keyword = keyword_match.group(1)
                
                # 如果关键词已存在，合并门店信息
                if keyword in keyword_dict:
                    existing_reply = keyword_dict[keyword]["reply"]
                    # 提取现有回复中的门店信息
                    guide_split = f"\n\n{store_guide_text}"
                    existing_stores = existing_reply.split("查询到以下可用店铺：\n\n")[1].split(guide_split)[0]
                    # 合并门店信息
                    merged_stores = existing_stores + "\n" + store_name
                    reply_str = f"您好，根据您发送的信息，查询到以下可用店铺：\n\n{merged_stores}\n\n{store_guide_text}"
                    keyword_dict[keyword]["reply"] = reply_str
                else:
                    # 新关键词，直接添加
                    reply_str = f"您好，根据您发送的信息，查询到以下可用店铺：\n\n{store_name}\n\n{store_guide_text}"
                    keyword_dict[keyword] = {
                        "keyword": keyword,
                        "reply": reply_str,
                        "item_id": item_id,
                        "type": "text",
                        "image_url": None
                    }

            # 按城市分组
            if city not in city_stores:
                city_stores[city] = []
            city_stores[city].append(store_name)

        # 添加城市关键词回复
        for city, stores in city_stores.items():
            # 如果城市名与已有关键词重复，合并门店信息
            if city in keyword_dict:
                existing_reply = keyword_dict[city]["reply"]
                # 提取现有回复中的门店信息
                guide_split = f"\n\n{store_guide_text}"
                existing_stores = existing_reply.split("查询到以下可用店铺：\n\n")[1].split(guide_split)[0]
                # 合并门店信息（去重）
                all_stores = existing_stores.split("\n") + stores
                unique_stores = list(dict.fromkeys(all_stores))  # 保持顺序的去重
                reply_text = "\n".join(unique_stores)
                reply_str = f"您好，根据您发送的信息，查询到以下可用店铺：\n\n{reply_text}\n\n{store_guide_text}"
                keyword_dict[city]["reply"] = reply_str
            else:
                # 新城市关键词
                reply_text = "\n".join(stores)
                reply_str = f"您好，根据您发送的信息，查询到以下可用店铺：\n\n{reply_text}\n\n{store_guide_text}"
                keyword_dict[city] = {
                    "keyword": city,
                    "reply": reply_str,
                    "item_id": item_id,
                    "type": "text",
                    "image_url": None
                }

        # 将字典转换为列表返回
        return list(keyword_dict.values())
    
    except Exception as e:
        logger.error(f"解析Excel文件失败: {str(e)}")
        raise HTTPException(status_code=400, detail=f"解析Excel文件失败: {str(e)}")


def generate_keywords_from_crawler_data(shop_list: List[str], city_list: List[str]) -> List[Dict[str, Any]]:
    """
    从爬虫抓取的门店数据生成关键词回复列表
    
    参数:
        shop_list: 门店名称列表
        city_list: 城市名称列表
    
    返回:
        包含关键词回复字典的列表
    """
    try:
        # 从系统设置中获取门店识别成功后的引导话术
        from db_manager import db_manager
        store_guide_text = db_manager.get_system_setting('store_guide_text')
        if not store_guide_text:
            store_guide_text = "上述店铺是可用的，直接拍就行"  # 默认话术
        
        keyword_dict = {}
        city_stores = {}
        
        # 处理门店列表
        for i, shop_name in enumerate(shop_list):
            if i < len(city_list):
                city = city_list[i]
            else:
                city = "未知城市"
            
            shop_name = str(shop_name).strip()
            city = str(city).strip()
            
            if not shop_name:
                continue
            
            # 从门店名称提取关键词（括号内的内容，移除'店'字）
            keyword_match = re.search(r'（(.+?)店）', shop_name)
            if keyword_match:
                keyword = keyword_match.group(1)
                
                # 如果关键词已存在，合并门店信息
                if keyword in keyword_dict:
                    existing_reply = keyword_dict[keyword]["reply"]
                    # 提取现有回复中的门店信息
                    guide_split = f"\n\n{store_guide_text}"
                    existing_stores = existing_reply.split("查询到以下可用店铺：\n\n")[1].split(guide_split)[0]
                    # 合并门店信息
                    merged_stores = existing_stores + "\n" + shop_name
                    reply_str = f"您好，根据您发送的信息，查询到以下可用店铺：\n\n{merged_stores}\n\n{store_guide_text}"
                    keyword_dict[keyword]["reply"] = reply_str
                else:
                    # 新关键词，直接添加
                    reply_str = f"您好，根据您发送的信息，查询到以下可用店铺：\n\n{shop_name}\n\n{store_guide_text}"
                    keyword_dict[keyword] = {
                        "keyword": keyword,
                        "reply": reply_str,
                        "item_id": "",  # 门店词库不绑定特定商品
                        "type": "text",
                        "image_url": None
                    }
            
            # 按城市分组
            if city not in city_stores:
                city_stores[city] = []
            city_stores[city].append(shop_name)
        3
        # 添加城市关键词回复
        for city, stores in city_stores.items():
            # 如果城市名与已有关键词重复，合并门店信息
            if city in keyword_dict:
                existing_reply = keyword_dict[city]["reply"]
                existing_stores_list = []
                
                # 提取现有回复中的门店信息
                if "查询到以下可用店铺：\n\n" in existing_reply and store_guide_text in existing_reply:
                    try:
                        guide_split = f"\n\n{store_guide_text}"
                        existing_stores_text = existing_reply.split("查询到以下可用店铺：\n\n")[1].split(guide_split)[0]
                        existing_stores_list = [store.strip() for store in existing_stores_text.split("\n") if store.strip()]
                    except (IndexError, AttributeError):
                        # 如果提取失败，说明格式不正确，忽略现有门店信息
                        existing_stores_list = []
                
                # 合并门店信息（去重）
                all_stores = existing_stores_list + stores
                unique_stores = list(dict.fromkeys(all_stores))  # 保持顺序的去重
                
                # 检查门店数量是否超过20条
                if len(unique_stores) > 20:
                    reply_str = "您好，根据您发送的信息，查询到可用门店过多，请发送详细的店名（参考美团上门店的名字）"
                else:
                    reply_text = "\n".join(unique_stores)
                    reply_str = f"您好，根据您发送的信息，查询到以下可用店铺：\n\n{reply_text}\n\n{store_guide_text}"
                keyword_dict[city]["reply"] = reply_str
            else:
                # 新城市关键词
                # 检查门店数量是否超过20条
                if len(stores) > 20:
                    reply_str = "您好，根据您发送的信息，查询到可用门店过多，请发送详细的店名（参考美团上门店的名字）"
                else:
                    reply_text = "\n".join(stores)
                    reply_str = f"您好，根据您发送的信息，查询到以下可用店铺：\n\n{reply_text}\n\n{store_guide_text}"
                keyword_dict[city] = {
                    "keyword": city,
                    "reply": reply_str,
                    "item_id": "",  # 门店词库不绑定特定商品
                    "type": "text",
                    "image_url": None
                }
        
        # 将字典转换为列表返回
        return list(keyword_dict.values())
        
    except Exception as e:
        logger.error(f"从爬虫数据生成关键词失败: {e}")
        return []


# 任务状态跟踪
task_status = {}

# 定期清理过期任务状态
async def cleanup_expired_tasks():
    """定期清理过期的任务状态"""
    while True:
        try:
            current_time = time.time()
            expired_tasks = []
            
            for task_id, status in task_status.items():
                # 清理超过1小时的完成/失败任务
                if (status.get("completed_at", 0) > 0 and current_time - status["completed_at"] > 3600) or \
                   (status.get("failed_at", 0) > 0 and current_time - status["failed_at"] > 3600) or \
                   (status.get("created_at", 0) > 0 and current_time - status["created_at"] > 7200):  # 2小时超时
                    expired_tasks.append(task_id)
            
            for task_id in expired_tasks:
                del task_status[task_id]
                logger.debug(f"清理过期任务: {task_id}")
            
            await asyncio.sleep(1800)  # 每30分钟清理一次
        except Exception as e:
            logger.error(f"清理过期任务失败: {e}")
            await asyncio.sleep(1800)

# 清理任务将在服务器启动时启动

async def process_excel_import_async(task_id: str, library_id: int, keyword_data_list: List[Dict[str, Any]], 
                                   library_name: str, current_user: Dict[str, Any]):
    """异步处理Excel导入任务"""
    try:
        # 更新任务状态
        task_status[task_id] = {
            "status": "processing",
            "progress": 0,
            "total": len(keyword_data_list),
            "message": "正在处理Excel数据...",
            "library_name": library_name,
            "created_at": time.time()
        }
        
        # 分批处理关键词，避免长时间锁定数据库
        batch_size = 100  # 增加批次大小，减少处理频率
        added_count = 0
        
        for i in range(0, len(keyword_data_list), batch_size):
            batch = keyword_data_list[i:i + batch_size]
            
            # 更新进度（减少更新频率）
            batch_num = i // batch_size + 1
            total_batches = (len(keyword_data_list) + batch_size - 1) // batch_size
            task_status[task_id]["progress"] = i + len(batch)
            task_status[task_id]["message"] = f"正在处理第 {batch_num}/{total_batches} 批数据..."
            
            # 批量添加
            success = db_manager.add_keywords_to_library(library_id, batch)
            if success:
                added_count += len(batch)
            
            # 适当休眠，避免过度占用资源
            await asyncio.sleep(0.2)  # 增加休眠时间
        
        # 任务完成
        task_status[task_id] = {
            "status": "completed",
            "progress": len(keyword_data_list),
            "total": len(keyword_data_list),
            "message": "导入完成",
            "added": added_count,
            "library_name": library_name,
            "completed_at": time.time()
        }
        
        log_with_user('info', f"Excel异步导入完成: library_id={library_id}, 添加数量: {added_count}", current_user)
        
    except Exception as e:
        # 任务失败
        task_status[task_id] = {
            "status": "failed",
            "progress": 0,
            "total": len(keyword_data_list),
            "message": f"导入失败: {str(e)}",
            "library_name": library_name,
            "failed_at": time.time()
        }
        logger.error(f"Excel异步导入失败: {e}")

async def process_crawler_import_async(task_id: str, library_id: int, sku_id: str, mt_token: str,
                                     library_name: str, current_user: Dict[str, Any]):
    """异步处理爬虫抓取任务"""
    try:
        # 更新任务状态
        task_status[task_id] = {
            "status": "processing",
            "progress": 0,
            "total": 100,  # 预估进度
            "message": "正在抓取门店信息...",
            "library_name": library_name,
            "created_at": time.time()
        }
        
        # 执行爬虫抓取
        from GetMtShopNameList import auto_get_shops_main
        
        task_status[task_id]["progress"] = 30
        task_status[task_id]["message"] = "正在连接美团API..."
        
        crawler_result = auto_get_shops_main(sku_id, mt_token)
        if not crawler_result['success']:
            raise Exception(f"爬虫抓取失败: {crawler_result.get('error', '未知错误')}")
        
        task_status[task_id]["progress"] = 60
        task_status[task_id]["message"] = "正在生成关键词..."
        
        # 从爬虫结果生成关键词数据
        keyword_data_list = generate_keywords_from_crawler_data(
            crawler_result['shopList'], 
            crawler_result['cityNameList']
        )
        
        if not keyword_data_list:
            raise Exception("未抓取到有效的门店信息")
        
        task_status[task_id]["total"] = len(keyword_data_list)
        task_status[task_id]["progress"] = 70
        task_status[task_id]["message"] = "正在保存关键词..."
        
        # 分批处理关键词
        batch_size = 100  # 增加批次大小，减少处理频率
        added_count = 0
        
        for i in range(0, len(keyword_data_list), batch_size):
            batch = keyword_data_list[i:i + batch_size]
            
            # 更新进度（减少更新频率）
            batch_num = i // batch_size + 1
            total_batches = (len(keyword_data_list) + batch_size - 1) // batch_size
            progress = 70 + ((i + len(batch)) / len(keyword_data_list)) * 30
            task_status[task_id]["progress"] = int(progress)
            task_status[task_id]["message"] = f"正在保存第 {batch_num}/{total_batches} 批关键词..."
            
            # 批量添加
            success = db_manager.add_keywords_to_library(library_id, batch)
            if success:
                added_count += len(batch)
            
            # 适当休眠
            await asyncio.sleep(0.2)  # 增加休眠时间
        
        # 任务完成
        task_status[task_id] = {
            "status": "completed",
            "progress": len(keyword_data_list),
            "total": len(keyword_data_list),
            "message": "抓取完成",
            "added": added_count,
            "library_name": library_name,
            "completed_at": time.time()
        }
        
        log_with_user('info', f"爬虫异步抓取完成: library_id={library_id}, 添加数量: {added_count}", current_user)
        
    except Exception as e:
        # 任务失败
        task_status[task_id] = {
            "status": "failed",
            "progress": 0,
            "total": 100,
            "message": f"抓取失败: {str(e)}",
            "library_name": library_name,
            "failed_at": time.time()
        }
        logger.error(f"爬虫异步抓取失败: {e}")


def update_existing_store_keywords_guide_text(new_guide_text: str) -> int:
    """
    更新所有现有门店关键词的引导话术
    
    参数:
        new_guide_text: 新的引导话术文本
    
    返回:
        更新的关键词数量
    """
    from db_manager import db_manager
    import re
    
    try:
        updated_count = 0
        
        # 获取所有关键词
        with db_manager.lock:
            cursor = db_manager.conn.cursor()
            cursor.execute("SELECT cookie_id, keyword, reply, item_id, type, image_url FROM keywords WHERE type = 'text'")
            keywords = cursor.fetchall()
            
            for keyword_data in keywords:
                cookie_id, keyword, reply, item_id, keyword_type, image_url = keyword_data
                
                # 检查是否是门店关键词回复（包含特定格式）
                if reply and "查询到以下可用店铺：" in reply:
                    # 使用正则表达式替换引导话术部分
                    # 匹配格式: "查询到以下可用店铺：\n\n{店铺列表}\n\n{旧引导话术}"
                    pattern = r'(查询到以下可用店铺：\n\n.*?)\n\n.*$'
                    match = re.search(pattern, reply, re.DOTALL)
                    
                    if match:
                        # 构建新的回复内容
                        store_list_part = match.group(1)
                        new_reply = f"{store_list_part}\n\n{new_guide_text}"
                        
                        # 更新数据库（使用 cookie_id 和 keyword 作为复合键）
                        cursor.execute(
                            "UPDATE keywords SET reply = %s WHERE cookie_id = %s AND keyword = %s",
                            (new_reply, cookie_id, keyword)
                        )
                        updated_count += 1
            
            db_manager.conn.commit()
            logger.info(f"成功更新 {updated_count} 个门店关键词的引导话术")
            
        return updated_count
        
    except Exception as e:
        logger.error(f"更新门店关键词引导话术失败: {e}")
        if db_manager.conn:
            db_manager.conn.rollback()
        return 0


def match_reply_with_balance_check(cookie_id: str, message: str) -> Tuple[Optional[str], str]:
    """根据 cookie_id 及消息内容匹配回复，带余额检查和扣费
    返回 (reply_content, status) 其中 status 可能是:
    - 'success': 匹配成功且扣费成功
    - 'insufficient_balance': 余额不足
    - 'no_match': 没有匹配到关键词
    - 'disabled': 账号被禁用
    - 'error': 其他错误
    """
    mgr = cookie_manager.manager
    if mgr is None:
        return None, 'error'

    # 检查账号是否启用
    if not mgr.get_cookie_status(cookie_id):
        return None, 'disabled'  # 禁用的账号不参与自动回复

    # 检查用户余额是否足够进行关键词匹配（需要1聚合豆）
    from db_manager import db_manager
    user_id = db_manager.get_user_id_by_cookie(cookie_id)
    if not user_id:
        logger.error(f"【{cookie_id}】无法获取用户ID，跳过关键词匹配")
        return None, 'error'
    
    current_balance = db_manager.get_user_balance(user_id)
    if current_balance < 1.0:
        logger.warning(f"【{cookie_id}】用户余额不足(当前:{current_balance}聚合豆，需要:1聚合豆)，跳过关键词匹配")
        return None, 'insufficient_balance'

    # 优先账号级关键字
    if mgr.get_keywords(cookie_id):
        for k, r in mgr.get_keywords(cookie_id):
            if k in message:
                # 关键词匹配成功，扣除1聚合豆
                balance_sufficient = db_manager.check_and_consume_balance(
                    user_id=user_id,
                    amount=1.0,
                    description=f"关键词匹配回复 - 关键词:{k}",
                    order_id=None
                )
                
                if balance_sufficient:
                    logger.info(f"【{cookie_id}】账号级关键词匹配成功，已扣除1聚合豆")
                    return r, 'success'
                else:
                    logger.warning(f"【{cookie_id}】关键词匹配成功但扣费失败，跳过回复")
                    return None, 'insufficient_balance'

    # 全局关键字
    for k, r in KEYWORDS_MAPPING:
        if k in message:
            # 全局关键词匹配成功，扣除1聚合豆
            balance_sufficient = db_manager.check_and_consume_balance(
                user_id=user_id,
                amount=1.0,
                description=f"全局关键词匹配回复 - 关键词:{k}",
                order_id=None
            )
            
            if balance_sufficient:
                logger.info(f"【{cookie_id}】全局关键词匹配成功，已扣除1聚合豆")
                return r, 'success'
            else:
                logger.warning(f"【{cookie_id}】全局关键词匹配成功但扣费失败，跳过回复")
                return None, 'insufficient_balance'
    return None, 'no_match'

def match_reply(cookie_id: str, message: str) -> Optional[str]:
    """根据 cookie_id 及消息内容匹配回复
    只有启用的账号才会匹配关键字回复
    """
    reply, status = match_reply_with_balance_check(cookie_id, message)
    return reply


async def add_delayed_guide_task(cookie_id: str, user_id: str, chat_id: str, item_id: str = None):
    """添加延迟引导话术任务"""
    try:
        from db_manager import db_manager
        
        # 检查是否启用延迟引导功能
        enabled = db_manager.get_system_setting('delayed_guide_enabled')
        if enabled != 'true':
            logger.debug("延迟引导功能已禁用")
            return
        
        # 获取延迟时间设置
        delay_setting = db_manager.get_system_setting('delayed_guide_delay_seconds')
        delay_seconds = int(delay_setting) if delay_setting and delay_setting.isdigit() else 60
        
        # 取消该对话中之前的所有待发送任务
        db_manager.cancel_delayed_guide_tasks(cookie_id, user_id, chat_id)
        
        # 添加新的延迟引导任务
        task_id = db_manager.add_delayed_guide_task(
            cookie_id, user_id, chat_id, item_id, delay_seconds
        )
        
        if task_id > 0:
            logger.info(f"API成功添加延迟引导任务: {task_id}, 将在 {delay_seconds} 秒后检查")
        else:
            logger.warning("API添加延迟引导任务失败")
            
    except Exception as e:
        logger.error(f"API添加延迟引导任务异常: {e}")


class RequestModel(BaseModel):
    cookie_id: str
    msg_time: str
    user_url: str
    send_user_id: str
    send_user_name: str
    item_id: str
    send_message: str
    chat_id: str


class ResponseData(BaseModel):
    send_msg: str


class ResponseModel(BaseModel):
    code: int
    data: ResponseData


app = FastAPI(
    title="Xianyu Auto Reply API",
    version="1.0.0",
    description="闲鱼自动回复系统API",
    docs_url="/docs",
    redoc_url="/redoc"
)

# 初始化文件日志收集器
setup_file_logging()

# 添加一条测试日志
logger.info("Web服务器启动，文件日志收集器已初始化")

# 启动事件
@app.on_event("startup")
async def startup_event():
    """应用启动时的初始化任务"""
    # 启动任务状态清理
    asyncio.create_task(cleanup_expired_tasks())
    logger.info("异步任务清理器已启动")

# 添加请求日志中间件
@app.middleware("http")
async def log_requests(request, call_next):
    start_time = time.time()

    # 获取用户信息
    user_info = "未登录"
    try:
        # 从请求头中获取Authorization
        auth_header = request.headers.get("Authorization")
        if auth_header and auth_header.startswith("Bearer "):
            token = auth_header.split(" ")[1]
            if token in SESSION_TOKENS:
                token_data = SESSION_TOKENS[token]
                # 检查token是否过期
                if time.time() - token_data['timestamp'] <= TOKEN_EXPIRE_TIME:
                    user_info = f"【{token_data['username']}#{token_data['user_id']}】"
    except Exception:
        pass

    logger.info(f"🌐 {user_info} API请求: {request.method} {request.url.path}")

    response = await call_next(request)

    process_time = time.time() - start_time
    logger.info(f"✅ {user_info} API响应: {request.method} {request.url.path} - {response.status_code} ({process_time:.3f}s)")

    return response

# 提供前端静态文件
import os
static_dir = os.path.join(os.path.dirname(__file__), 'static')
if not os.path.exists(static_dir):
    os.makedirs(static_dir, exist_ok=True)

app.mount('/static', StaticFiles(directory=static_dir), name='static')

# 确保图片上传目录存在
uploads_dir = os.path.join(static_dir, 'uploads', 'images')
if not os.path.exists(uploads_dir):
    os.makedirs(uploads_dir, exist_ok=True)
    logger.info(f"创建图片上传目录: {uploads_dir}")

# 健康检查端点
@app.get('/health')
async def health_check():
    """健康检查端点，用于Docker健康检查和负载均衡器"""
    try:
        # 检查Cookie管理器状态
        manager_status = "ok" if cookie_manager.manager is not None else "error"

        # 检查数据库连接
        from db_manager import db_manager
        try:
            db_manager.get_all_cookies()
            db_status = "ok"
        except Exception:
            db_status = "error"

        # 获取系统状态
        import psutil
        cpu_percent = psutil.cpu_percent(interval=1)
        memory_info = psutil.virtual_memory()

        status = {
            "status": "healthy" if manager_status == "ok" and db_status == "ok" else "unhealthy",
            "timestamp": time.time(),
            "services": {
                "cookie_manager": manager_status,
                "database": db_status
            },
            "system": {
                "cpu_percent": cpu_percent,
                "memory_percent": memory_info.percent,
                "memory_available": memory_info.available
            }
        }

        if status["status"] == "unhealthy":
            raise HTTPException(status_code=503, detail=status)

        return status

    except Exception as e:
        return {
            "status": "unhealthy",
            "timestamp": time.time(),
            "error": str(e)
        }


# 重定向根路径到登录页面
@app.get('/', response_class=HTMLResponse)
async def root():
    login_path = os.path.join(static_dir, 'login.html')
    if os.path.exists(login_path):
        with open(login_path, 'r', encoding='utf-8') as f:
            return HTMLResponse(f.read())
    else:
        return HTMLResponse('<h3>Login page not found</h3>')


# 登录页面路由
@app.get('/login.html', response_class=HTMLResponse)
async def login_page():
    login_path = os.path.join(static_dir, 'login.html')
    if os.path.exists(login_path):
        with open(login_path, 'r', encoding='utf-8') as f:
            return HTMLResponse(f.read())
    else:
        return HTMLResponse('<h3>Login page not found</h3>')


# 注册页面路由
@app.get('/register.html', response_class=HTMLResponse)
async def register_page():
    # 检查注册是否开启
    from db_manager import db_manager
    registration_enabled = db_manager.get_system_setting('registration_enabled')
    if registration_enabled != 'true':
        return HTMLResponse('''
        <!DOCTYPE html>
        <html>
        <head>
            <title>注册已关闭</title>
            <meta charset="utf-8">
            <style>
                body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
                .message { color: #666; font-size: 18px; }
                .back-link { margin-top: 20px; }
                .back-link a { color: #007bff; text-decoration: none; }
            </style>
        </head>
        <body>
            <h2>🚫 注册功能已关闭</h2>
            <p class="message">系统管理员已关闭用户注册功能</p>
            <div class="back-link">
                <a href="/">← 返回首页</a>
            </div>
        </body>
        </html>
        ''', status_code=403)

    register_path = os.path.join(static_dir, 'register.html')
    if os.path.exists(register_path):
        with open(register_path, 'r', encoding='utf-8') as f:
            return HTMLResponse(f.read())
    else:
        return HTMLResponse('<h3>Register page not found</h3>')


# 管理页面（不需要服务器端认证，由前端JavaScript处理）
@app.get('/admin', response_class=HTMLResponse)
async def admin_page():
    index_path = os.path.join(static_dir, 'index.html')
    if not os.path.exists(index_path):
        return HTMLResponse('<h3>No front-end found</h3>')
    with open(index_path, 'r', encoding='utf-8') as f:
        return HTMLResponse(f.read())


# 用户管理页面路由
@app.get('/user_management.html', response_class=HTMLResponse)
async def user_management_page():
    page_path = os.path.join(static_dir, 'user_management.html')
    if os.path.exists(page_path):
        with open(page_path, 'r', encoding='utf-8') as f:
            return HTMLResponse(f.read())
    else:
        return HTMLResponse('<h3>User management page not found</h3>')


# 日志管理页面路由
@app.get('/log_management.html', response_class=HTMLResponse)
async def log_management_page():
    page_path = os.path.join(static_dir, 'log_management.html')
    if os.path.exists(page_path):
        with open(page_path, 'r', encoding='utf-8') as f:
            return HTMLResponse(f.read())
    else:
        return HTMLResponse('<h3>Log management page not found</h3>')


# 数据管理页面路由
@app.get('/data_management.html', response_class=HTMLResponse)
async def data_management_page():
    page_path = os.path.join(static_dir, 'data_management.html')
    if os.path.exists(page_path):
        with open(page_path, 'r', encoding='utf-8') as f:
            return HTMLResponse(f.read())
    else:
        return HTMLResponse('<h3>Data management page not found</h3>')


# 登录接口
@app.post('/login')
async def login(request: LoginRequest):
    from db_manager import db_manager

    # 判断登录方式
    if request.username and request.password:
        # 用户名/密码登录
        logger.info(f"【{request.username}】尝试用户名登录")

        # 统一使用用户表验证（包括admin用户）
        if db_manager.verify_user_password(request.username, request.password):
            user = db_manager.get_user_by_username(request.username)
            if user:
                # 生成token
                token = generate_token()
                SESSION_TOKENS[token] = {
                    'id': user['id'],  # 添加id字段以兼容订单管理
                    'user_id': user['id'],
                    'username': user['username'],
                    'is_admin': (user['username'] == ADMIN_USERNAME),  # 添加is_admin字段
                    'timestamp': time.time()
                }

                # 区分管理员和普通用户的日志
                if user['username'] == ADMIN_USERNAME:
                    logger.info(f"【{user['username']}#{user['id']}】登录成功（管理员）")
                else:
                    logger.info(f"【{user['username']}#{user['id']}】登录成功")

                return LoginResponse(
                    success=True,
                    token=token,
                    message="登录成功",
                    user_id=user['id'],
                    username=user['username'],
                    is_admin=(user['username'] == ADMIN_USERNAME)
                )

        logger.warning(f"【{request.username}】登录失败：用户名或密码错误")
        return LoginResponse(
            success=False,
            message="用户名或密码错误"
        )

    elif request.email and request.password:
        # 邮箱/密码登录
        logger.info(f"【{request.email}】尝试邮箱密码登录")

        user = db_manager.get_user_by_email(request.email)
        if user and db_manager.verify_user_password(user['username'], request.password):
            # 生成token
            token = generate_token()
            SESSION_TOKENS[token] = {
                'id': user['id'],  # 添加id字段以兼容订单管理
                'user_id': user['id'],
                'username': user['username'],
                'is_admin': (user['username'] == ADMIN_USERNAME),  # 添加is_admin字段
                'timestamp': time.time()
            }

            logger.info(f"【{user['username']}#{user['id']}】邮箱登录成功")

            return LoginResponse(
                success=True,
                token=token,
                message="登录成功",
                user_id=user['id'],
                username=user['username'],
                is_admin=(user['username'] == ADMIN_USERNAME)
            )

        logger.warning(f"【{request.email}】邮箱登录失败：邮箱或密码错误")
        return LoginResponse(
            success=False,
            message="邮箱或密码错误"
        )

    elif request.email and request.verification_code:
        # 邮箱/验证码登录
        logger.info(f"【{request.email}】尝试邮箱验证码登录")

        # 验证邮箱验证码
        if not db_manager.verify_email_code(request.email, request.verification_code, 'login'):
            logger.warning(f"【{request.email}】验证码登录失败：验证码错误或已过期")
            return LoginResponse(
                success=False,
                message="验证码错误或已过期"
            )

        # 获取用户信息
        user = db_manager.get_user_by_email(request.email)
        if not user:
            logger.warning(f"【{request.email}】验证码登录失败：用户不存在")
            return LoginResponse(
                success=False,
                message="用户不存在"
            )

        # 生成token
        token = generate_token()
        SESSION_TOKENS[token] = {
            'id': user['id'],  # 添加id字段以兼容订单管理
            'user_id': user['id'],
            'username': user['username'],
            'is_admin': (user['username'] == ADMIN_USERNAME),  # 添加is_admin字段
            'timestamp': time.time()
        }

        logger.info(f"【{user['username']}#{user['id']}】验证码登录成功")

        return LoginResponse(
            success=True,
            token=token,
            message="登录成功",
            user_id=user['id'],
            username=user['username'],
            is_admin=(user['username'] == ADMIN_USERNAME)
        )

    else:
        return LoginResponse(
            success=False,
            message="请提供有效的登录信息"
        )


# 验证token接口
@app.get('/verify')
async def verify(user_info: Optional[Dict[str, Any]] = Depends(verify_token)):
    if user_info:
        from db_manager import db_manager
        user_id = user_info['user_id']
        
        # 获取用户角色和权限信息
        roles = db_manager.get_user_roles(user_id)
        permissions = db_manager.get_user_permissions(user_id)
        menus = db_manager.get_user_menus(user_id)
        
        # 如果是管理员，确保拥有所有权限
        if user_info['username'] == ADMIN_USERNAME:
            all_permissions = db_manager.get_all_permissions()
            permissions = [perm['name'] for perm in all_permissions]
        
        return {
            "authenticated": True,
            "user_id": user_info['user_id'],
            "username": user_info['username'],
            "is_admin": user_info['username'] == ADMIN_USERNAME,
            "roles": roles,
            "permissions": permissions,
            "menus": menus
        }
    return {"authenticated": False}


# 登出接口
@app.post('/logout')
async def logout(credentials: Optional[HTTPAuthorizationCredentials] = Depends(security)):
    if credentials and credentials.credentials in SESSION_TOKENS:
        del SESSION_TOKENS[credentials.credentials]
    return {"message": "已登出"}


# 修改管理员密码接口
@app.post('/change-admin-password')
async def change_admin_password(request: ChangePasswordRequest, admin_user: Dict[str, Any] = Depends(verify_admin_token)):
    from db_manager import db_manager

    try:
        # 验证当前密码（使用用户表验证）
        if not db_manager.verify_user_password('admin', request.current_password):
            return {"success": False, "message": "当前密码错误"}

        # 更新密码（使用用户表更新）
        success = db_manager.update_user_password('admin', request.new_password)

        if success:
            logger.info(f"【admin#{admin_user['user_id']}】管理员密码修改成功")
            return {"success": True, "message": "密码修改成功"}
        else:
            return {"success": False, "message": "密码修改失败"}

    except Exception as e:
        logger.error(f"修改管理员密码异常: {e}")
        return {"success": False, "message": "系统错误"}


# 生成图形验证码接口
@app.post('/generate-captcha')
async def generate_captcha(request: CaptchaRequest):
    from db_manager import db_manager

    try:
        # 生成图形验证码
        captcha_text, captcha_image = db_manager.generate_captcha()

        if not captcha_image:
            return CaptchaResponse(
                success=False,
                captcha_image="",
                session_id=request.session_id,
                message="图形验证码生成失败"
            )

        # 保存验证码到数据库
        if db_manager.save_captcha(request.session_id, captcha_text):
            return CaptchaResponse(
                success=True,
                captcha_image=captcha_image,
                session_id=request.session_id,
                message="图形验证码生成成功"
            )
        else:
            return CaptchaResponse(
                success=False,
                captcha_image="",
                session_id=request.session_id,
                message="图形验证码保存失败"
            )

    except Exception as e:
        logger.error(f"生成图形验证码失败: {e}")
        return CaptchaResponse(
            success=False,
            captcha_image="",
            session_id=request.session_id,
            message="图形验证码生成失败"
        )


# 验证图形验证码接口
@app.post('/verify-captcha')
async def verify_captcha(request: VerifyCaptchaRequest):
    from db_manager import db_manager

    try:
        if db_manager.verify_captcha(request.session_id, request.captcha_code):
            return VerifyCaptchaResponse(
                success=True,
                message="图形验证码验证成功"
            )
        else:
            return VerifyCaptchaResponse(
                success=False,
                message="图形验证码错误或已过期"
            )

    except Exception as e:
        logger.error(f"验证图形验证码失败: {e}")
        return VerifyCaptchaResponse(
            success=False,
            message="图形验证码验证失败"
        )


# 发送验证码接口（需要先验证图形验证码）
@app.post('/send-verification-code')
async def send_verification_code(request: SendCodeRequest):
    from db_manager import db_manager

    try:
        # 检查是否已验证图形验证码
        # 通过检查数据库中是否存在已验证的图形验证码记录
        with db_manager.lock:
            cursor = db_manager.conn.cursor()
            current_time = time.time()

            # 查找最近5分钟内该session_id的验证记录
            # 由于验证成功后验证码会被删除，我们需要另一种方式来跟踪验证状态
            # 这里我们检查该session_id是否在最近验证过（通过检查是否有已删除的记录）

            # 为了简化，我们要求前端在验证图形验证码成功后立即发送邮件验证码
            # 或者我们可以在验证成功后设置一个临时标记
            pass

        # 根据验证码类型进行不同的检查
        if request.type == 'register':
            # 注册验证码：检查邮箱是否已注册
            existing_user = db_manager.get_user_by_email(request.email)
            if existing_user:
                return SendCodeResponse(
                    success=False,
                    message="该邮箱已被注册"
                )
        elif request.type == 'login':
            # 登录验证码：检查邮箱是否存在
            existing_user = db_manager.get_user_by_email(request.email)
            if not existing_user:
                return SendCodeResponse(
                    success=False,
                    message="该邮箱未注册"
                )

        # 生成验证码
        code = db_manager.generate_verification_code()

        # 保存验证码到数据库
        if not db_manager.save_verification_code(request.email, code, request.type):
            return SendCodeResponse(
                success=False,
                message="验证码保存失败，请稍后重试"
            )

        # 发送验证码邮件
        if await db_manager.send_verification_email(request.email, code):
            return SendCodeResponse(
                success=True,
                message="验证码已发送到您的邮箱，请查收"
            )
        else:
            return SendCodeResponse(
                success=False,
                message="验证码发送失败，请检查邮箱地址或稍后重试"
            )

    except Exception as e:
        logger.error(f"发送验证码失败: {e}")
        return SendCodeResponse(
            success=False,
            message="发送验证码失败，请稍后重试"
        )


# 用户注册接口
@app.post('/register')
async def register(request: RegisterRequest):
    from db_manager import db_manager

    # 检查注册是否开启
    registration_enabled = db_manager.get_system_setting('registration_enabled')
    if registration_enabled != 'true':
        logger.warning(f"【{request.username}】注册失败: 注册功能已关闭")
        return RegisterResponse(
            success=False,
            message="注册功能已关闭，请联系管理员"
        )

    try:
        logger.info(f"【{request.username}】尝试注册，邮箱: {request.email}")

        # 验证邮箱验证码
        if not db_manager.verify_email_code(request.email, request.verification_code):
            logger.warning(f"【{request.username}】注册失败: 验证码错误或已过期")
            return RegisterResponse(
                success=False,
                message="验证码错误或已过期"
            )

        # 检查用户名是否已存在
        existing_user = db_manager.get_user_by_username(request.username)
        if existing_user:
            logger.warning(f"【{request.username}】注册失败: 用户名已存在")
            return RegisterResponse(
                success=False,
                message="用户名已存在"
            )

        # 检查邮箱是否已注册
        existing_email = db_manager.get_user_by_email(request.email)
        if existing_email:
            logger.warning(f"【{request.username}】注册失败: 邮箱已被注册")
            return RegisterResponse(
                success=False,
                message="该邮箱已被注册"
            )

        # 创建用户
        if db_manager.create_user(request.username, request.email, request.password):
            logger.info(f"【{request.username}】注册成功")
            return RegisterResponse(
                success=True,
                message="注册成功，请登录"
            )
        else:
            logger.error(f"【{request.username}】注册失败: 数据库操作失败")
            return RegisterResponse(
                success=False,
                message="注册失败，请稍后重试"
            )

    except Exception as e:
        logger.error(f"【{request.username}】注册异常: {e}")
        return RegisterResponse(
            success=False,
            message="注册失败，请稍后重试"
        )


@app.post("/xianyu/reply", response_model=ResponseModel)
async def xianyu_reply(req: RequestModel):
    # 检查商品是否已配置关键词（只有配置了关键词的商品才能进行自动回复）
    from db_manager import db_manager
    if not db_manager.has_item_keywords(req.cookie_id, req.item_id):
        logger.info(f"【API】账号 {req.cookie_id} 商品 {req.item_id} 未配置关键词，跳过自动回复")
        raise HTTPException(status_code=404, detail="该商品未配置关键词，无法进行自动回复")
    
    msg_template, match_status = match_reply_with_balance_check(req.cookie_id, req.send_message)
    is_default_reply = False

    # 根据匹配状态处理
    if match_status == 'insufficient_balance':
        logger.warning(f"【API】账号 {req.cookie_id} 用户余额不足，无法进行关键词自动回复")
        raise HTTPException(status_code=402, detail="余额不足，无法进行自动回复")
    elif match_status == 'error':
        logger.error(f"【API】账号 {req.cookie_id} 关键词匹配时发生错误")
        raise HTTPException(status_code=500, detail="系统错误")
    elif match_status == 'success':
        # 关键词匹配成功，处理后续逻辑（扣费已在match_reply_with_balance_check中完成）
        from db_manager import db_manager
        # 关键词匹配成功，重置该对话的未匹配回复计数
        db_manager.reset_unmatch_reply_count(req.cookie_id, req.send_user_id, req.chat_id)
        
        # 添加延迟引导话术任务
        await add_delayed_guide_task(req.cookie_id, req.send_user_id, req.chat_id, req.item_id)

    if not msg_template:
        # 检查商品专属回复（如果尚未发送过）
        if not db_manager.has_chat_first_replied(req.cookie_id, req.chat_id):
            exclusive_reply = db_manager.get_item_exclusive_reply(req.cookie_id, req.item_id)
            if exclusive_reply and exclusive_reply.get('enabled', False):
                # 使用商品专属回复语
                msg_template = exclusive_reply.get('reply_content', '')
                is_default_reply = True
                # 标记对话已经回复过专属回复
                db_manager.mark_chat_has_replied(req.cookie_id, req.chat_id)
                # 重置该对话的未匹配回复计数
                db_manager.reset_unmatch_reply_count(req.cookie_id, req.send_user_id, req.chat_id)
                logger.info(f"【API】对话 {req.chat_id} 使用商品专属回复语")
        
        # 如果没有专属回复或已发送过，检查是否为对话的首次回复
        if not msg_template:
            is_first_reply = db_manager.is_chat_first_reply(req.cookie_id, req.chat_id)

            if is_first_reply:
                # 首次回复：使用账号管理设置的默认回复内容
                default_reply_settings = db_manager.get_default_reply(req.cookie_id)

                if default_reply_settings and default_reply_settings.get('enabled', False):
                    # 检查是否开启了"只回复一次"功能
                    if default_reply_settings.get('reply_once', False):
                        # 检查是否已经回复过这个chat_id
                        if db_manager.has_default_reply_record(req.cookie_id, req.chat_id):
                            raise HTTPException(status_code=404, detail="该对话已使用默认回复，不再重复回复")

                    msg_template = default_reply_settings.get('reply_content', '')
                    is_default_reply = True
                    # 标记对话已经回复过
                    db_manager.mark_chat_first_reply(req.cookie_id, req.chat_id)
                    logger.info(f"【API】对话 {req.chat_id} 首次回复，使用账号默认回复")
                else:
                    # 如果账号没有设置默认回复，使用系统未匹配回复
                    unmatch_reply = db_manager.get_system_setting('unmatch_default_reply')
                    msg_template = unmatch_reply if unmatch_reply else "抱歉，根据您发送的内容，未能识别到可用门店"
                    # 标记对话已经回复过
                    db_manager.mark_chat_first_reply(req.cookie_id, req.chat_id)
                    logger.info(f"【API】对话 {req.chat_id} 首次回复，使用系统未匹配回复")
        else:
            # 非首次回复：检查未匹配回复次数限制
            # 从系统配置中获取最大未匹配回复次数限制，默认为3次
            max_unmatch_count = int(db_manager.get_system_setting('max_unmatch_reply_count') or 3)
            if not db_manager.check_unmatch_reply_limit(req.cookie_id, req.send_user_id, req.chat_id, max_count=max_unmatch_count):
                # 检查是否已发送过最终提醒消息
                if not db_manager.has_sent_final_reminder(req.cookie_id, req.send_user_id, req.chat_id):
                    # 返回最终提醒消息
                    final_reminder = "多次未匹配成功则表示您发送的目标门店不可用（或者您可以发送\"转人工\"，人工客服将为您手动查询）"
                    # 标记已发送最终提醒消息
                    db_manager.mark_final_reminder_sent(req.cookie_id, req.send_user_id, req.chat_id)
                    logger.info(f"【API】用户 {req.send_user_id} 在对话 {req.chat_id} 中未匹配回复次数已达上限({max_unmatch_count}次)，返回最终提醒消息")
                    return {"code": 200, "data": {"send_msg": final_reminder}}
                else:
                    logger.info(f"【API】用户 {req.send_user_id} 在对话 {req.chat_id} 中未匹配回复次数已达上限({max_unmatch_count}次)，已发送过最终提醒消息，跳过发送")
                    raise HTTPException(status_code=404, detail=f"该对话未匹配回复次数已达上限({max_unmatch_count}次)，暂停发送")
            
            # 使用系统设置中的未匹配回复
            unmatch_reply = db_manager.get_system_setting('unmatch_default_reply')
            msg_template = unmatch_reply if unmatch_reply else "抱歉，根据您发送的内容，未能识别到可用门店"
            
            # 记录未匹配回复次数
            db_manager.increment_unmatch_reply_count(req.cookie_id, req.send_user_id, req.chat_id)
            logger.info(f"【API】对话 {req.chat_id} 非首次回复，使用系统未匹配回复，当前次数：{db_manager.get_unmatch_reply_count(req.cookie_id, req.send_user_id, req.chat_id)}")

    # 按占位符格式化
    try:
        send_msg = msg_template.format(
            send_user_id=req.send_user_id,
            send_user_name=req.send_user_name,
            send_message=req.send_message,
        )
    except Exception:
        # 如果格式化失败，返回原始内容
        send_msg = msg_template

    # 如果是默认回复且开启了"只回复一次"，记录回复记录
    if is_default_reply:
        from db_manager import db_manager
        default_reply_settings = db_manager.get_default_reply(req.cookie_id)
        if default_reply_settings and default_reply_settings.get('reply_once', False):
            db_manager.add_default_reply_record(req.cookie_id, req.chat_id)

    return {"code": 200, "data": {"send_msg": send_msg}}

# ------------------------- 账号 / 关键字管理接口 -------------------------


class CookieIn(BaseModel):
    id: str
    value: str


class CookieStatusIn(BaseModel):
    enabled: bool


class DefaultReplyIn(BaseModel):
    enabled: bool
    reply_content: Optional[str] = None
    reply_once: bool = False


class NotificationChannelIn(BaseModel):
    name: str
    type: str = "dingtalk"
    config: str


class NotificationWxidRequest(BaseModel):
    notification_wxid: str


class NotificationChannelUpdate(BaseModel):
    name: str
    config: str
    enabled: bool = True


class MessageNotificationIn(BaseModel):
    channel_id: int
    enabled: bool = True


class SystemSettingIn(BaseModel):
    key: str
    value: str
    description: Optional[str] = None


class SystemSettingUpdateIn(BaseModel):
    value: str
    description: Optional[str] = None





@app.get("/cookies")
def list_cookies(current_user: Dict[str, Any] = Depends(get_current_user)):
    if cookie_manager.manager is None:
        return []

    # 获取当前用户的cookies
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)
    return list(user_cookies.keys())


@app.get("/cookies/details")
def get_cookies_details(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取所有Cookie的详细信息（包括值和状态）"""
    if cookie_manager.manager is None:
        return []

    # 获取当前用户的cookies
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)

    result = []
    for cookie_id, cookie_value in user_cookies.items():
        cookie_enabled = cookie_manager.manager.get_cookie_status(cookie_id)
        auto_confirm = db_manager.get_auto_confirm(cookie_id)
        pause_enabled = db_manager.get_pause_enabled(cookie_id)
        # 获取备注信息
        cookie_details = db_manager.get_cookie_details(cookie_id)
        remark = cookie_details.get('remark', '') if cookie_details else ''

        result.append({
            'id': cookie_id,
            'value': cookie_value,
            'enabled': cookie_enabled,
            'auto_confirm': auto_confirm,
            'remark': remark,
            'pause_duration': cookie_details.get('pause_duration', 10) if cookie_details else 10,
            'pauseEnabled': pause_enabled,
            'token_status': cookie_details.get('token_status', 'valid') if cookie_details else 'valid',
            'token_failed_at': cookie_details.get('token_failed_at') if cookie_details else None,
            'notification_wxid': cookie_details.get('notification_wxid') if cookie_details else None
        })
    return result


@app.get("/cookies/details-optimized")
@cache_result(ttl=120, key_prefix="cookies_details")  # 缓存2分钟
async def get_cookies_details_optimized(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取所有Cookie的详细信息（优化版本，减少数据库查询）"""
    if cookie_manager.manager is None:
        return []

    try:
        # 使用批量查询获取账号信息和关键词统计
        user_id = current_user['user_id']
        from db_manager import db_manager
        
        # 并行执行数据库查询和cookie状态检查
        accounts_data = await asyncio.get_event_loop().run_in_executor(
            thread_pool, 
            db_manager.get_cookies_with_keywords_batch, 
            user_id
        )
        
        # 批量获取cookie状态（避免逐个查询）
        cookie_statuses = {}
        if cookie_manager.manager:
            for account in accounts_data:
                cookie_statuses[account['id']] = cookie_manager.manager.get_cookie_status(account['id'])
        
        # 构建返回结果
        result = []
        for account in accounts_data:
            cookie_id = account['id']
            result.append({
                'id': cookie_id,
                'value': account['value'],
                'enabled': cookie_statuses.get(cookie_id, True),
                'auto_confirm': account['auto_confirm'],
                'remark': account['remark'],
                'pause_duration': account['pause_duration'],
                'pauseEnabled': account['pause_enabled'],
                'token_status': account['token_status'],
                'token_failed_at': account['token_failed_at'],
                'notification_wxid': account['notification_wxid'],
                'keyword_count': account.get('keywords_count', 0),  # 使用前端期望的字段名
                'items_count': account.get('items_count', 0)  # 商品数量统计
            })
        
        return result
        
    except Exception as e:
        logger.error(f"获取账号详情失败: {e}")
        # 降级到原来的方法
        def get_cookies_details_sync():
            return get_cookies_details(current_user)
        
        return await asyncio.get_event_loop().run_in_executor(
            thread_pool, 
            get_cookies_details_sync
        )


@app.get("/cookies/details-with-settings")
@cache_result(ttl=60, key_prefix="cookies_details_settings")  # 缓存1分钟
async def get_cookies_details_with_settings(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取所有Cookie的详细信息，包含默认回复、AI回复和暂停设置（性能优化版本）"""
    if cookie_manager.manager is None:
        return []

    try:
        user_id = current_user['user_id']
        from db_manager import db_manager
        
        # 并行执行数据库查询
        accounts_data = await asyncio.get_event_loop().run_in_executor(
            thread_pool, 
            db_manager.get_cookies_with_keywords_batch, 
            user_id
        )
        
        # 批量获取所有设置信息
        default_replies = await asyncio.get_event_loop().run_in_executor(
            thread_pool, 
            db_manager.get_all_default_replies
        )
        
        ai_reply_settings = await asyncio.get_event_loop().run_in_executor(
            thread_pool, 
            db_manager.get_all_ai_reply_settings
        )
        
        # 批量获取cookie状态
        cookie_statuses = {}
        if cookie_manager.manager:
            for account in accounts_data:
                cookie_statuses[account['id']] = cookie_manager.manager.get_cookie_status(account['id'])
        
        # 构建返回结果
        result = []
        for account in accounts_data:
            cookie_id = account['id']
            
            # 获取默认回复设置
            default_reply = next((dr for dr in default_replies if dr.get('cookie_id') == cookie_id), None)
            if default_reply is None:
                default_reply = {'enabled': False, 'reply_content': '', 'reply_once': False}
            
            # 获取AI回复设置
            ai_reply = next((ar for ar in ai_reply_settings if ar.get('cookie_id') == cookie_id), None)
            if ai_reply is None:
                ai_reply = {'ai_enabled': False, 'model_name': 'qwen-plus'}
            
            result.append({
                'id': cookie_id,
                'value': account['value'],
                'enabled': cookie_statuses.get(cookie_id, True),
                'auto_confirm': account['auto_confirm'],
                'remark': account['remark'],
                'pause_duration': account['pause_duration'],
                'pauseEnabled': account['pause_enabled'],
                'token_status': account['token_status'],
                'token_failed_at': account['token_failed_at'],
                'notification_wxid': account['notification_wxid'],
                'keyword_count': account.get('keywords_count', 0),
                'items_count': account.get('items_count', 0),
                # 新增的设置信息
                'defaultReply': default_reply,
                'aiReply': ai_reply,
                'pause_enabled': account['pause_enabled']  # 暂停功能开关
            })
        
        return result
        
    except Exception as e:
        logger.error(f"获取账号详情和设置失败: {e}")
        # 降级到分别获取
        try:
            accounts = await get_cookies_details_optimized(current_user)
            # 为每个账号添加设置信息
            for account in accounts:
                try:
                    # 获取默认回复
                    default_reply = db_manager.get_default_reply(account['id'])
                    if default_reply is None:
                        default_reply = {'enabled': False, 'reply_content': '', 'reply_once': False}
                    
                    # 获取AI回复设置
                    ai_reply = db_manager.get_ai_reply_settings(account['id'])
                    if ai_reply is None:
                        ai_reply = {'ai_enabled': False, 'model_name': 'qwen-plus'}
                    
                    account['defaultReply'] = default_reply
                    account['aiReply'] = ai_reply
                    account['pause_enabled'] = account.get('pauseEnabled', True)
                except Exception as setting_error:
                    logger.error(f"获取账号 {account['id']} 设置失败: {setting_error}")
                    account['defaultReply'] = {'enabled': False, 'reply_content': '', 'reply_once': False}
                    account['aiReply'] = {'ai_enabled': False, 'model_name': 'qwen-plus'}
                    account['pause_enabled'] = True
            
            return accounts
        except Exception as fallback_error:
            logger.error(f"降级获取账号详情失败: {fallback_error}")
            return []


@app.post("/cookies")
def add_cookie(item: CookieIn, current_user: Dict[str, Any] = Depends(get_current_user)):
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 添加cookie时绑定到当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager

        log_with_user('info', f"尝试添加Cookie: {item.id}, 当前用户ID: {user_id}, 用户名: {current_user.get('username', 'unknown')}", current_user)

        # 检查cookie是否已存在且属于其他用户
        existing_cookies = db_manager.get_all_cookies()
        if item.id in existing_cookies:
            # 检查是否属于当前用户
            user_cookies = db_manager.get_all_cookies(user_id)
            if item.id not in user_cookies:
                log_with_user('warning', f"Cookie ID冲突: {item.id} 已被其他用户使用", current_user)
                raise HTTPException(status_code=400, detail="该Cookie ID已被其他用户使用")

        # 保存到数据库时指定用户ID
        db_manager.save_cookie(item.id, item.value, user_id)

        # 获取账号名称并填入备注
        try:
            from getXyUserNick import get_xy_user_nick
            account_name = get_xy_user_nick(item.value)
            if account_name:
                # 更新备注字段
                db_manager.update_cookie_remark(item.id, account_name)
                log_with_user('info', f"获取到账号名称: {account_name}, 已填入备注", current_user)
            else:
                log_with_user('warning', f"未能获取到账号名称，备注将保持为空", current_user)
        except Exception as e:
            log_with_user('warning', f"获取账号名称失败: {str(e)}，备注将保持为空", current_user)

        # 添加到CookieManager，同时指定用户ID
        cookie_manager.manager.add_cookie(item.id, item.value, user_id=user_id)
        log_with_user('info', f"Cookie添加成功: {item.id}", current_user)
        
        # 清除相关缓存
        invalidate_user_cache(user_id)
        
        return {"msg": "success"}
    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"添加Cookie失败: {item.id} - {str(e)}", current_user)
        raise HTTPException(status_code=400, detail=str(e))


@app.put('/cookies/{cid}')
def update_cookie(cid: str, item: CookieIn, current_user: Dict[str, Any] = Depends(get_current_user)):
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail='CookieManager 未就绪')
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 更新cookie时保持用户绑定
        db_manager.save_cookie(cid, item.value, user_id)
        cookie_manager.manager.update_cookie(cid, item.value)
        return {'msg': 'updated'}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


# ========================= 扫码登录相关接口 =========================

@app.post("/qr-login/generate")
async def generate_qr_code(current_user: Dict[str, Any] = Depends(get_current_user)):
    """生成扫码登录二维码"""
    try:
        log_with_user('info', "请求生成扫码登录二维码", current_user)

        result = await qr_login_manager.generate_qr_code()

        if result['success']:
            log_with_user('info', f"扫码登录二维码生成成功: {result['session_id']}", current_user)
        else:
            log_with_user('warning', f"扫码登录二维码生成失败: {result.get('message', '未知错误')}", current_user)

        return result

    except Exception as e:
        log_with_user('error', f"生成扫码登录二维码异常: {str(e)}", current_user)
        return {'success': False, 'message': f'生成二维码失败: {str(e)}'}


@app.get("/qr-login/check/{session_id}")
async def check_qr_code_status(session_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """检查扫码登录状态"""
    try:
        # 清理过期会话
        qr_login_manager.cleanup_expired_sessions()

        # 获取会话状态
        status_info = qr_login_manager.get_session_status(session_id)

        if status_info['status'] == 'success':
            # 登录成功，处理Cookie
            cookies_info = qr_login_manager.get_session_cookies(session_id)
            if cookies_info:
                account_info = await process_qr_login_cookies(
                    cookies_info['cookies'],
                    cookies_info['unb'],
                    current_user
                )
                status_info['account_info'] = account_info

                log_with_user('info', f"扫码登录成功处理完成: {session_id}, 账号: {account_info.get('account_id', 'unknown')}", current_user)

        return status_info

    except Exception as e:
        log_with_user('error', f"检查扫码登录状态异常: {str(e)}", current_user)
        return {'status': 'error', 'message': str(e)}


async def process_qr_login_cookies(cookies: str, unb: str, current_user: Dict[str, Any]) -> Dict[str, Any]:
    """处理扫码登录获取的Cookie"""
    try:
        user_id = current_user['user_id']

        # 检查是否已存在相同unb的账号
        existing_cookies = db_manager.get_all_cookies(user_id)
        existing_account_id = None

        for account_id, cookie_value in existing_cookies.items():
            try:
                # 解析现有Cookie中的unb
                existing_cookie_dict = trans_cookies(cookie_value)
                if existing_cookie_dict.get('unb') == unb:
                    existing_account_id = account_id
                    break
            except:
                continue

        if existing_account_id:
            # 更新现有账号的Cookie
            db_manager.save_cookie(existing_account_id, cookies, user_id)

            # 获取账号名称并更新备注
            try:
                from getXyUserNick import get_xy_user_nick
                account_name = get_xy_user_nick(cookies)
                if account_name:
                    db_manager.update_cookie_remark(existing_account_id, account_name)
                    log_with_user('info', f"更新现有账号名称: {account_name}, 已填入备注", current_user)
            except Exception as e:
                log_with_user('warning', f"获取现有账号名称失败: {str(e)}", current_user)

            # 更新cookie_manager中的Cookie
            if cookie_manager.manager:
                cookie_manager.manager.update_cookie(existing_account_id, cookies)

            log_with_user('info', f"扫码登录更新现有账号Cookie: {existing_account_id}, UNB: {unb}", current_user)

            return {
                'account_id': existing_account_id,
                'is_new_account': False
            }
        else:
            # 创建新账号，使用unb作为账号ID
            account_id = unb

            # 确保账号ID唯一
            counter = 1
            original_account_id = account_id
            while account_id in existing_cookies:
                account_id = f"{original_account_id}_{counter}"
                counter += 1

            # 保存新账号
            db_manager.save_cookie(account_id, cookies, user_id)

            # 获取账号名称并填入备注
            try:
                from getXyUserNick import get_xy_user_nick
                account_name = get_xy_user_nick(cookies)
                if account_name:
                    db_manager.update_cookie_remark(account_id, account_name)
                    log_with_user('info', f"获取到新账号名称: {account_name}, 已填入备注", current_user)
                else:
                    log_with_user('warning', f"未能获取到新账号名称，备注将保持为空", current_user)
            except Exception as e:
                log_with_user('warning', f"获取新账号名称失败: {str(e)}，备注将保持为空", current_user)

            # 添加到cookie_manager
            if cookie_manager.manager:
                cookie_manager.manager.add_cookie(account_id, cookies)

            log_with_user('info', f"扫码登录创建新账号: {account_id}, UNB: {unb}", current_user)

            return {
                'account_id': account_id,
                'is_new_account': True
            }

    except Exception as e:
        log_with_user('error', f"处理扫码登录Cookie失败: {str(e)}", current_user)
        raise e


@app.put('/cookies/{cid}/status')
def update_cookie_status(cid: str, status_data: CookieStatusIn, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新账号的启用/禁用状态"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail='CookieManager 未就绪')
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        cookie_manager.manager.update_cookie_status(cid, status_data.enabled)
        
        # 清理相关缓存，确保数据一致性
        # 由于缓存键包含复杂的哈希值，我们需要清理所有相关的缓存前缀
        cache_prefixes_to_clear = [
            "cookies_details",
            "cookies_details_settings", 
            "dashboard_stats"
        ]
        for prefix in cache_prefixes_to_clear:
            app_cache.clear_by_prefix(prefix)
        
        return {'msg': 'status updated', 'enabled': status_data.enabled}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


# ------------------------- 默认回复管理接口 -------------------------

@app.get('/default-replies/{cid}')
def get_default_reply(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取指定账号的默认回复设置"""
    from db_manager import db_manager
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        result = db_manager.get_default_reply(cid)
        if result is None:
            # 如果没有设置，返回默认值
            return {'enabled': False, 'reply_content': '', 'reply_once': False}
        return result
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.put('/default-replies/{cid}')
def update_default_reply(cid: str, reply_data: DefaultReplyIn, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新指定账号的默认回复设置"""
    from db_manager import db_manager
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        db_manager.save_default_reply(cid, reply_data.enabled, reply_data.reply_content, reply_data.reply_once)
        return {'msg': 'default reply updated', 'enabled': reply_data.enabled, 'reply_once': reply_data.reply_once}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.get('/default-replies')
def get_all_default_replies(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户所有账号的默认回复设置"""
    from db_manager import db_manager
    try:
        # 只返回当前用户的默认回复设置
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        all_replies = db_manager.get_all_default_replies()
        # 过滤只属于当前用户的回复设置
        user_replies = {cid: reply for cid, reply in all_replies.items() if cid in user_cookies}
        return user_replies
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.delete('/default-replies/{cid}')
def delete_default_reply(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """删除指定账号的默认回复设置"""
    from db_manager import db_manager
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        success = db_manager.delete_default_reply(cid)
        if success:
            return {'msg': 'default reply deleted'}
        else:
            raise HTTPException(status_code=400, detail='删除失败')
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.post('/default-replies/{cid}/clear-records')
def clear_default_reply_records(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """清空指定账号的默认回复记录"""
    from db_manager import db_manager
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        db_manager.clear_default_reply_records(cid)
        return {'msg': 'default reply records cleared'}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ------------------------- 通知渠道管理接口 -------------------------

@app.get('/notification-channels')
def get_notification_channels(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取所有通知渠道"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        return db_manager.get_notification_channels(user_id)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.post('/notification-channels')
def create_notification_channel(channel_data: NotificationChannelIn, current_user: Dict[str, Any] = Depends(get_current_user)):
    """创建通知渠道"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        channel_id = db_manager.create_notification_channel(
            channel_data.name,
            channel_data.type,
            channel_data.config,
            user_id
        )
        return {'msg': 'notification channel created', 'id': channel_id}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


@app.get('/notification-channels/{channel_id}')
def get_notification_channel(channel_id: int, _: None = Depends(require_auth)):
    """获取指定通知渠道"""
    from db_manager import db_manager
    try:
        channel = db_manager.get_notification_channel(channel_id)
        if not channel:
            raise HTTPException(status_code=404, detail='通知渠道不存在')
        return channel
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.put('/notification-channels/{channel_id}')
def update_notification_channel(channel_id: int, channel_data: NotificationChannelUpdate, _: None = Depends(require_auth)):
    """更新通知渠道"""
    from db_manager import db_manager
    try:
        success = db_manager.update_notification_channel(
            channel_id,
            channel_data.name,
            channel_data.config,
            channel_data.enabled
        )
        if success:
            return {'msg': 'notification channel updated'}
        else:
            raise HTTPException(status_code=404, detail='通知渠道不存在')
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


@app.delete('/notification-channels/{channel_id}')
def delete_notification_channel(channel_id: int, _: None = Depends(require_auth)):
    """删除通知渠道"""
    from db_manager import db_manager
    try:
        success = db_manager.delete_notification_channel(channel_id)
        if success:
            return {'msg': 'notification channel deleted'}
        else:
            raise HTTPException(status_code=404, detail='通知渠道不存在')
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ------------------------- 消息通知配置接口 -------------------------

@app.get('/message-notifications')
def get_all_message_notifications(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户所有账号的消息通知配置"""
    from db_manager import db_manager
    try:
        # 只返回当前用户的消息通知配置
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        all_notifications = db_manager.get_all_message_notifications()
        # 过滤只属于当前用户的通知配置
        user_notifications = {cid: notifications for cid, notifications in all_notifications.items() if cid in user_cookies}
        return user_notifications
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.get('/message-notifications/{cid}')
def get_account_notifications(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取指定账号的消息通知配置"""
    from db_manager import db_manager
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        return db_manager.get_message_notifications(cid)
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.post('/message-notifications/{cid}')
def set_message_notification(cid: str, notification_data: MessageNotificationIn, current_user: Dict[str, Any] = Depends(get_current_user)):
    """设置账号的消息通知"""
    from db_manager import db_manager
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 检查通知渠道是否存在
        channel = db_manager.get_notification_channel(notification_data.channel_id)
        if not channel:
            raise HTTPException(status_code=404, detail='通知渠道不存在')

        success = db_manager.set_message_notification(cid, notification_data.channel_id, notification_data.enabled)
        if success:
            return {'msg': 'message notification set'}
        else:
            raise HTTPException(status_code=400, detail='设置失败')
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.delete('/message-notifications/account/{cid}')
def delete_account_notifications(cid: str, _: None = Depends(require_auth)):
    """删除账号的所有消息通知配置"""
    from db_manager import db_manager
    try:
        success = db_manager.delete_account_notifications(cid)
        if success:
            return {'msg': 'account notifications deleted'}
        else:
            raise HTTPException(status_code=404, detail='账号通知配置不存在')
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.delete('/message-notifications/{notification_id}')
def delete_message_notification(notification_id: int, _: None = Depends(require_auth)):
    """删除消息通知配置"""
    from db_manager import db_manager
    try:
        success = db_manager.delete_message_notification(notification_id)
        if success:
            return {'msg': 'message notification deleted'}
        else:
            raise HTTPException(status_code=404, detail='通知配置不存在')
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ------------------------- 系统设置接口 -------------------------

@app.get('/system-settings')
def get_system_settings(_: None = Depends(require_auth)):
    """获取系统设置（排除敏感信息）"""
    from db_manager import db_manager
    try:
        settings = db_manager.get_all_system_settings()
        # 移除敏感信息
        if 'admin_password_hash' in settings:
            del settings['admin_password_hash']
        return settings
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))





@app.put('/system-settings/{key}')
def update_system_setting(key: str, setting_data: SystemSettingUpdateIn, _: None = Depends(require_auth)):
    """更新系统设置"""
    from db_manager import db_manager
    try:
        # 禁止直接修改密码哈希
        if key == 'admin_password_hash':
            raise HTTPException(status_code=400, detail='请使用密码修改接口')

        success = db_manager.set_system_setting(key, setting_data.value, setting_data.description)
        if success:
            # 如果更新的是门店引导话术设置，同时更新所有现有的门店关键词回复
            if key == 'store_guide_text':
                updated_count = update_existing_store_keywords_guide_text(setting_data.value)
                return {
                    'msg': 'system setting updated', 
                    'updated_keywords': updated_count,
                    'note': f'已同时更新 {updated_count} 个现有门店关键词的引导话术'
                }
            
            return {'msg': 'system setting updated'}
        else:
            raise HTTPException(status_code=400, detail='更新失败')
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ------------------------- 注册设置接口 -------------------------

@app.get('/registration-status')
def get_registration_status():
    """获取注册开关状态（公开接口，无需认证）"""
    from db_manager import db_manager
    try:
        enabled_str = db_manager.get_system_setting('registration_enabled')
        logger.info(f"从数据库获取的注册设置值: '{enabled_str}'")  # 调试信息

        # 如果设置不存在，默认为开启
        if enabled_str is None:
            enabled_bool = True
            message = '注册功能已开启'
        else:
            enabled_bool = enabled_str == 'true'
            message = '注册功能已开启' if enabled_bool else '注册功能已关闭'

        logger.info(f"解析后的注册状态: enabled={enabled_bool}, message='{message}'")  # 调试信息

        return {
            'enabled': enabled_bool,
            'message': message
        }
    except Exception as e:
        logger.error(f"获取注册状态失败: {e}")
        return {'enabled': True, 'message': '注册功能已开启'}  # 出错时默认开启


class RegistrationSettingUpdate(BaseModel):
    enabled: bool


class AdminUserCreateRequest(BaseModel):
    username: str
    email: str
    password: str


@app.put('/registration-settings')
def update_registration_settings(setting_data: RegistrationSettingUpdate, admin_user: Dict[str, Any] = Depends(require_admin)):
    """更新注册开关设置（仅管理员）"""
    from db_manager import db_manager
    try:
        enabled = setting_data.enabled
        success = db_manager.set_system_setting(
            'registration_enabled',
            'true' if enabled else 'false',
            '是否开启用户注册'
        )
        if success:
            log_with_user('info', f"更新注册设置: {'开启' if enabled else '关闭'}", admin_user)
            return {
                'success': True,
                'enabled': enabled,
                'message': f"注册功能已{'开启' if enabled else '关闭'}"
            }
        else:
            raise HTTPException(status_code=500, detail='更新注册设置失败')
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"更新注册设置失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))





@app.delete("/cookies/{cid}")
def remove_cookie(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        cookie_manager.manager.remove_cookie(cid)
        return {"msg": "removed"}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


class AutoConfirmUpdate(BaseModel):
    auto_confirm: bool


class RemarkUpdate(BaseModel):
    remark: str


class PauseDurationUpdate(BaseModel):
    pause_duration: int


class PauseEnabledUpdate(BaseModel):
    pause_enabled: bool


@app.put("/cookies/{cid}/auto-confirm")
def update_auto_confirm(cid: str, update_data: AutoConfirmUpdate, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新账号的自动确认发货设置"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 更新数据库中的auto_confirm设置
        success = db_manager.update_auto_confirm(cid, update_data.auto_confirm)
        if not success:
            raise HTTPException(status_code=500, detail="更新自动确认发货设置失败")

        # 通知CookieManager更新设置（如果账号正在运行）
        if hasattr(cookie_manager.manager, 'update_auto_confirm_setting'):
            cookie_manager.manager.update_auto_confirm_setting(cid, update_data.auto_confirm)

        return {
            "msg": "success",
            "auto_confirm": update_data.auto_confirm,
            "message": f"自动确认发货已{'开启' if update_data.auto_confirm else '关闭'}"
        }
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/cookies/{cid}/auto-confirm")
def get_auto_confirm(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取账号的自动确认发货设置"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 获取auto_confirm设置
        auto_confirm = db_manager.get_auto_confirm(cid)
        return {
            "auto_confirm": auto_confirm,
            "message": f"自动确认发货当前{'开启' if auto_confirm else '关闭'}"
        }
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.put("/cookies/{cid}/remark")
def update_cookie_remark(cid: str, update_data: RemarkUpdate, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新账号备注"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 更新备注
        success = db_manager.update_cookie_remark(cid, update_data.remark)
        if success:
            log_with_user('info', f"更新账号备注: {cid} -> {update_data.remark}", current_user)
            return {
                "message": "备注更新成功",
                "remark": update_data.remark
            }
        else:
            raise HTTPException(status_code=500, detail="备注更新失败")
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/cookies/{cid}/remark")
def get_cookie_remark(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取账号备注"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 获取Cookie详细信息（包含备注）
        cookie_details = db_manager.get_cookie_details(cid)
        if cookie_details:
            return {
                "remark": cookie_details.get('remark', ''),
                "message": "获取备注成功"
            }
        else:
            raise HTTPException(status_code=404, detail="账号不存在")
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.put("/cookies/{cid}/pause-duration")
def update_cookie_pause_duration(cid: str, update_data: PauseDurationUpdate, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新账号自动回复暂停时间"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 验证暂停时间范围（1-60分钟）
        if not (1 <= update_data.pause_duration <= 60):
            raise HTTPException(status_code=400, detail="暂停时间必须在1-60分钟之间")

        # 更新暂停时间
        success = db_manager.update_cookie_pause_duration(cid, update_data.pause_duration)
        if success:
            log_with_user('info', f"更新账号自动回复暂停时间: {cid} -> {update_data.pause_duration}分钟", current_user)
            return {
                "message": "暂停时间更新成功",
                "pause_duration": update_data.pause_duration
            }
        else:
            raise HTTPException(status_code=500, detail="暂停时间更新失败")
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/cookies/{cid}/pause-duration")
def get_cookie_pause_duration(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取账号自动回复暂停时间"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 获取暂停时间
        pause_duration = db_manager.get_cookie_pause_duration(cid)
        return {
            "pause_duration": pause_duration,
            "message": "获取暂停时间成功"
        }
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.put("/cookies/{cid}/pause-enabled")
def update_pause_enabled(cid: str, update_data: PauseEnabledUpdate, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新账号自动回复暂停功能开关"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 更新暂停功能开关
        success = db_manager.update_pause_enabled(cid, update_data.pause_enabled)
        if success:
            log_with_user('info', f"更新账号自动回复暂停功能开关: {cid} -> {'启用' if update_data.pause_enabled else '禁用'}", current_user)
            return {
                "message": f"暂停功能已{'启用' if update_data.pause_enabled else '禁用'}",
                "pause_enabled": update_data.pause_enabled
            }
        else:
            raise HTTPException(status_code=500, detail="暂停功能开关更新失败")
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/cookies/{cid}/permanently-paused-chats")
def get_permanently_paused_chats(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取指定账号的永久暂停会话列表"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        paused_chats = db_manager.get_permanently_paused_chats_by_cookie(cid)
        return {
            "success": True,
            "data": paused_chats
        }
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/cookies/{cid}/resume-chat/{chat_id}")
def resume_permanently_paused_chat(cid: str, chat_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """恢复永久暂停的会话"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 检查会话是否确实被永久暂停
        if not db_manager.is_chat_permanently_paused(chat_id):
            raise HTTPException(status_code=404, detail="该会话未被永久暂停")

        # 恢复会话
        from XianyuAutoAsync import pause_manager
        success = pause_manager.resume_permanently_paused_chat(chat_id, cid)
        
        if success:
            log_with_user('info', f"恢复永久暂停的会话: {cid} -> {chat_id}", current_user)
            return {
                "success": True,
                "message": "会话已恢复自动回复"
            }
        else:
            raise HTTPException(status_code=500, detail="恢复会话失败")
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.put("/cookies/{cid}/notification-wxid")
def update_cookie_notification_wxid(cid: str, request: NotificationWxidRequest, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新Cookie的通知wxid"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        success = db_manager.update_cookie_notification_wxid(cid, request.notification_wxid)

        if success:
            log_with_user('info', f"更新账号通知wxid: {cid} -> {request.notification_wxid or '(清空)'}", current_user)
            return {"msg": "通知wxid更新成功"}
        else:
            raise HTTPException(status_code=500, detail="更新失败")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"更新Cookie通知wxid失败: {e}")
        raise HTTPException(status_code=500, detail=f"更新失败: {str(e)}")


@app.get("/cookies/{cid}/pause-enabled")
def get_pause_enabled(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取账号自动回复暂停功能开关"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 获取暂停功能开关
        pause_enabled = db_manager.get_pause_enabled(cid)
        return {
            "pause_enabled": pause_enabled,
            "message": f"暂停功能当前{'启用' if pause_enabled else '禁用'}"
        }
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/cookies/{cid}/refresh-token-status")
def refresh_token_status(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """刷新账号Token状态"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cid not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 检查账号是否在运行
        if cid in cookie_manager.manager.tasks:
            # 账号正在运行，检查WebSocket连接状态
            task = cookie_manager.manager.tasks[cid]
            if task and not task.done():
                # 任务正在运行，假设连接正常，设置Token状态为有效
                db_manager.update_token_status(cid, 'valid')
                log_with_user('info', f"账号 {cid} 正在运行，Token状态已更新为有效", current_user)
                return {
                    "token_status": "valid",
                    "message": "账号正在运行，Token状态已更新为有效"
                }
            else:
                # 任务已结束，可能存在问题
                db_manager.update_token_status(cid, 'invalid')
                log_with_user('warning', f"账号 {cid} 任务已结束，Token状态已更新为失效", current_user)
                return {
                    "token_status": "invalid",
                    "message": "账号任务已结束，Token状态已更新为失效"
                }
        else:
            # 账号未运行，检查是否被禁用
            is_enabled = cookie_manager.manager.get_cookie_status(cid)
            if not is_enabled:
                # 账号被禁用
                current_status = db_manager.get_token_status(cid)
                return {
                    "token_status": current_status,
                    "message": f"账号已禁用，Token状态保持为: {current_status}"
                }
            else:
                # 账号启用但未运行，可能存在问题
                db_manager.update_token_status(cid, 'invalid')
                log_with_user('warning', f"账号 {cid} 启用但未运行，Token状态已更新为失效", current_user)
                return {
                    "token_status": "invalid",
                    "message": "账号启用但未运行，Token状态已更新为失效"
                }

    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"刷新Token状态失败: {cid} - {str(e)}", current_user)
        raise HTTPException(status_code=500, detail=str(e))


class KeywordIn(BaseModel):
    keywords: Dict[str, str]  # key -> reply

class KeywordWithItemIdIn(BaseModel):
    keywords: List[Dict[str, Any]]  # [{"keyword": str, "reply": str, "item_id": str}]


@app.get("/keywords/{cid}")
def get_keywords(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)

    if cid not in user_cookies:
        raise HTTPException(status_code=403, detail="无权限访问该Cookie")

    # 检查用户权限
    user_permissions = db_manager.get_user_permissions(user_id)
    is_admin = current_user['username'] == 'admin'
    has_manage_permission = 'auto_reply_manage' in user_permissions or is_admin

    # 直接从数据库获取所有关键词（避免重复计算）
    item_keywords = db_manager.get_keywords_with_item_id(cid)

    if not has_manage_permission:
        # 普通用户只能看到已配置关键词的商品信息，包含词库信息但不显示具体关键词和回复内容
        # 直接从数据库查询去重的商品ID和词库信息
        try:
            with db_manager.lock:
                cursor = db_manager.get_connection().cursor()
                # 使用GROUP_CONCAT来收集每个商品ID的所有词库名称
                cursor.execute('''
                SELECT k.item_id, 
                       GROUP_CONCAT(DISTINCT kl.name SEPARATOR ',') as library_names,
                       COUNT(k.id) as keyword_count
                FROM keywords k 
                LEFT JOIN keyword_libraries kl ON k.library_id = kl.id 
                WHERE k.cookie_id = %s AND k.item_id IS NOT NULL AND k.item_id != ''
                GROUP BY k.item_id
                ''', (cid,))
                
                items_info = []
                for row in cursor.fetchall():
                    item_id = row[0]
                    library_names = row[1]
                    keyword_count = row[2]
                    
                    # 获取商品信息
                    item_info = db_manager.get_item_info(cid, item_id)
                    
                    # 处理词库名称
                    libraries = []
                    if library_names:
                        libraries = [name.strip() for name in library_names.split(',') if name.strip()]
                    
                    items_info.append({
                        "item_id": item_id,
                        "item_title": item_info.get('item_title', '未知商品') if item_info else '未知商品',
                        "item_description": item_info.get('item_description', '') if item_info else '',
                        "has_keywords": True,
                        "type": "configured_item",
                        "libraries": libraries,
                        "keyword_count": keyword_count
                    })
                
                logger.info(f"普通用户API - 最终返回数据数量: {len(items_info)}")
                for item in items_info:
                    logger.info(f"返回商品: {item['item_id']}, 标题: {item['item_title']}, 词库: {item['libraries']}")
                return items_info
                
        except Exception as e:
            logger.error(f"普通用户API查询失败: {e}")
            return []
    else:
        # 管理员可以看到完整的关键词信息
        all_keywords = []
        for keyword, reply, item_id in item_keywords:
            all_keywords.append({
                "keyword": keyword,
                "reply": reply,
                "item_id": item_id,
                "type": "item" if item_id else "normal"
            })

        return all_keywords


@app.get("/keywords/{cid}/items-summary")
def get_keywords_items_summary(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取账号下已配置关键词的商品ID汇总信息（性能优化版本，不返回具体关键词内容）"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)

    if cid not in user_cookies:
        raise HTTPException(status_code=403, detail="无权限访问该Cookie")

    try:
        # 只获取商品ID汇总信息，不获取具体关键词内容
        with db_manager.lock:
            cursor = db_manager.get_connection().cursor()
            cursor.execute('''
            SELECT 
                k.item_id,
                COUNT(*) as keyword_count,
                GROUP_CONCAT(DISTINCT kl.name) as library_names
            FROM keywords k
            LEFT JOIN keyword_libraries kl ON k.library_id = kl.id
            WHERE k.cookie_id = %s AND k.item_id IS NOT NULL AND k.item_id != ''
            GROUP BY k.item_id
            ORDER BY k.item_id
            ''', (cid,))
            
            items_summary = []
            for row in cursor.fetchall():
                item_id = row[0]
                keyword_count = row[1]
                library_names = row[2].split(',') if row[2] else []
                
                # 获取商品信息
                item_info = db_manager.get_item_info(cid, item_id)
                
                items_summary.append({
                    'item_id': item_id,
                    'item_title': item_info.get('item_title', f'商品 {item_id}') if item_info else f'商品 {item_id}',
                    'keyword_count': keyword_count,
                    'libraries': [name.strip() for name in library_names if name.strip()],
                    'type': 'configured_item'
                })
            
            return items_summary
            
    except Exception as e:
        logger.error(f"获取商品汇总信息失败: {e}")
        raise HTTPException(status_code=500, detail="获取商品汇总信息失败")


@app.get("/keywords-with-item-id/{cid}")
def get_keywords_with_item_id(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取包含商品ID的关键词列表"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)

    if cid not in user_cookies:
        raise HTTPException(status_code=403, detail="无权限访问该Cookie")

    # 获取包含类型信息的关键词
    keywords = db_manager.get_keywords_with_type(cid)

    # 转换为前端需要的格式
    result = []
    for keyword_data in keywords:
        result.append({
            "keyword": keyword_data['keyword'],
            "reply": keyword_data['reply'],
            "item_id": keyword_data['item_id'] or "",
            "type": keyword_data['type'],
            "image_url": keyword_data['image_url']
        })

    return result


@app.post("/keywords/{cid}")
def update_keywords(cid: str, body: KeywordIn, current_user: Dict[str, Any] = Depends(require_permission('auto_reply_manage'))):
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)

    if cid not in user_cookies:
        log_with_user('warning', f"尝试操作其他用户的Cookie关键字: {cid}", current_user)
        raise HTTPException(status_code=403, detail="无权限操作该Cookie")

    kw_list = [(k, v) for k, v in body.keywords.items()]
    log_with_user('info', f"更新Cookie关键字: {cid}, 数量: {len(kw_list)}", current_user)

    cookie_manager.manager.update_keywords(cid, kw_list)
    log_with_user('info', f"Cookie关键字更新成功: {cid}", current_user)
    return {"msg": "updated", "count": len(kw_list)}


@app.post("/keywords-with-item-id/{cid}")
def update_keywords_with_item_id(cid: str, body: KeywordWithItemIdIn, current_user: Dict[str, Any] = Depends(require_permission('auto_reply_manage'))):
    """更新包含商品ID的关键词列表"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)

    if cid not in user_cookies:
        log_with_user('warning', f"尝试操作其他用户的Cookie关键字: {cid}", current_user)
        raise HTTPException(status_code=403, detail="无权限操作该Cookie")

    # 验证数据格式
    keywords_to_save = []
    keyword_set = set()  # 用于检查当前提交的关键词中是否有重复

    for kw_data in body.keywords:
        keyword = kw_data.get('keyword', '').strip()
        reply = kw_data.get('reply', '').strip()
        item_id = kw_data.get('item_id', '').strip() or None

        if not keyword or not reply:
            raise HTTPException(status_code=400, detail="关键词和回复内容不能为空")

        # 检查当前提交的关键词中是否有重复
        keyword_key = f"{keyword}|{item_id or ''}"
        if keyword_key in keyword_set:
            item_id_text = f"（商品ID: {item_id}）" if item_id else "（通用关键词）"
            raise HTTPException(status_code=400, detail=f"关键词 '{keyword}' {item_id_text} 在当前提交中重复")
        keyword_set.add(keyword_key)

        keywords_to_save.append((keyword, reply, item_id))

    # 保存关键词（只保存文本关键词，保留图片关键词）
    try:
        success = db_manager.save_text_keywords_only(cid, keywords_to_save)
        if not success:
            raise HTTPException(status_code=500, detail="保存关键词失败")
    except Exception as e:
        error_msg = str(e)
        if "UNIQUE constraint failed" in error_msg:
            # 解析具体的冲突信息
            if "keywords.cookie_id, keywords.keyword" in error_msg:
                raise HTTPException(status_code=400, detail="关键词重复！该关键词已存在（可能是图片关键词或文本关键词），请使用其他关键词")
            else:
                raise HTTPException(status_code=400, detail="关键词重复！请使用不同的关键词或商品ID组合")
        else:
            log_with_user('error', f"保存关键词时发生未知错误: {error_msg}", current_user)
            raise HTTPException(status_code=500, detail="保存关键词失败")

    log_with_user('info', f"更新Cookie关键字(含商品ID): {cid}, 数量: {len(keywords_to_save)}", current_user)
    return {"msg": "updated", "count": len(keywords_to_save)}


@app.get("/items/{cid}")
def get_items_list(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取指定账号的商品列表"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)

    if cid not in user_cookies:
        raise HTTPException(status_code=403, detail="无权限访问该Cookie")

    try:
        # 获取该账号的所有商品
        with db_manager.lock:
            cursor = db_manager.conn.cursor()
            cursor.execute('''
            SELECT item_id, item_title, item_price, created_at
            FROM item_info
            WHERE cookie_id = %s
            ORDER BY created_at DESC
            ''', (cid,))

            items = []
            for row in cursor.fetchall():
                items.append({
                    'item_id': row[0],
                    'item_title': row[1] or '未知商品',
                    'item_price': row[2] or '价格未知',
                    'created_at': row[3]
                })

            return {"items": items, "count": len(items)}

    except Exception as e:
        logger.error(f"获取商品列表失败: {e}")
        raise HTTPException(status_code=500, detail="获取商品列表失败")


@app.get("/keywords-export/{cid}")
def export_keywords(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """导出指定账号的关键词为Excel文件"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)

    if cid not in user_cookies:
        raise HTTPException(status_code=403, detail="无权限访问该Cookie")

    try:
        # 获取关键词数据（包含类型信息）
        keywords = db_manager.get_keywords_with_type(cid)

        # 创建DataFrame，只导出文本类型的关键词
        data = []
        for keyword_data in keywords:
            # 只导出文本类型的关键词
            if keyword_data.get('type', 'text') == 'text':
                data.append({
                    '关键词': keyword_data['keyword'],
                    '商品ID': keyword_data['item_id'] or '',
                    '关键词内容': keyword_data['reply']
                })

        # 如果没有数据，创建空的DataFrame但保留列名（作为模板）
        if not data:
            df = pd.DataFrame(columns=['关键词', '商品ID', '关键词内容'])
        else:
            df = pd.DataFrame(data)

        # 创建Excel文件
        output = io.BytesIO()
        with pd.ExcelWriter(output, engine='openpyxl') as writer:
            df.to_excel(writer, sheet_name='关键词数据', index=False)

            # 如果是空模板，添加一些示例说明
            if data == []:
                worksheet = writer.sheets['关键词数据']
                # 添加示例数据作为注释（从第2行开始）
                worksheet['A2'] = '你好'
                worksheet['B2'] = ''
                worksheet['C2'] = '您好！欢迎咨询，有什么可以帮助您的吗？'

                worksheet['A3'] = '价格'
                worksheet['B3'] = '123456'
                worksheet['C3'] = '这个商品的价格是99元，现在有优惠活动哦！'

                worksheet['A4'] = '发货'
                worksheet['B4'] = ''
                worksheet['C4'] = '我们会在24小时内发货，请耐心等待。'

                # 设置示例行的样式（浅灰色背景）
                from openpyxl.styles import PatternFill
                gray_fill = PatternFill(start_color='F0F0F0', end_color='F0F0F0', fill_type='solid')
                for row in range(2, 5):
                    for col in range(1, 4):
                        worksheet.cell(row=row, column=col).fill = gray_fill

        output.seek(0)

        # 生成文件名（使用URL编码处理中文）
        from urllib.parse import quote
        if not data:
            filename = f"keywords_template_{cid}_{int(time.time())}.xlsx"
        else:
            filename = f"keywords_{cid}_{int(time.time())}.xlsx"
        encoded_filename = quote(filename.encode('utf-8'))

        # 返回文件
        return StreamingResponse(
            io.BytesIO(output.read()),
            media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            headers={
                "Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}"
            }
        )

    except Exception as e:
        logger.error(f"导出关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"导出关键词失败: {str(e)}")








@app.post("/keywords/{cid}/image")
async def add_image_keyword(
    cid: str,
    keyword: str = Form(...),
    item_id: str = Form(default=""),
    image: UploadFile = File(...),
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """添加图片关键词"""
    logger.info(f"接收到图片关键词添加请求: cid={cid}, keyword={keyword}, item_id={item_id}")

    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查参数
    if not keyword or not keyword.strip():
        raise HTTPException(status_code=400, detail="关键词不能为空")

    if not image or not image.filename:
        raise HTTPException(status_code=400, detail="请选择图片文件")

    # 检查cookie是否属于当前用户
    cookie_details = db_manager.get_cookie_details(cid)
    if not cookie_details or cookie_details['user_id'] != current_user['user_id']:
        raise HTTPException(status_code=404, detail="账号不存在或无权限")

    try:
        logger.info(f"接收到图片关键词添加请求: cid={cid}, keyword={keyword}, item_id={item_id}, filename={image.filename}")

        # 验证图片文件
        if not image.content_type or not image.content_type.startswith('image/'):
            logger.warning(f"无效的图片文件类型: {image.content_type}")
            raise HTTPException(status_code=400, detail="请上传图片文件")

        # 读取图片数据
        image_data = await image.read()
        logger.info(f"读取图片数据成功，大小: {len(image_data)} bytes")

        # 保存图片
        image_url = image_manager.save_image(image_data, image.filename)
        if not image_url:
            logger.error("图片保存失败")
            raise HTTPException(status_code=400, detail="图片保存失败")

        logger.info(f"图片保存成功: {image_url}")

        # 先检查关键词是否已存在
        normalized_item_id = item_id if item_id and item_id.strip() else None
        if db_manager.check_keyword_duplicate(cid, keyword, normalized_item_id):
            # 删除已保存的图片
            image_manager.delete_image(image_url)
            if normalized_item_id:
                raise HTTPException(status_code=400, detail=f"关键词 '{keyword}' 在商品 '{normalized_item_id}' 中已存在")
            else:
                raise HTTPException(status_code=400, detail=f"通用关键词 '{keyword}' 已存在")

        # 保存图片关键词到数据库
        success = db_manager.save_image_keyword(cid, keyword, image_url, item_id or None)
        if not success:
            # 如果数据库保存失败，删除已保存的图片
            logger.error("数据库保存失败，删除已保存的图片")
            image_manager.delete_image(image_url)
            raise HTTPException(status_code=400, detail="图片关键词保存失败，请稍后重试")

        log_with_user('info', f"添加图片关键词成功: {cid}, 关键词: {keyword}", current_user)

        return {
            "msg": "图片关键词添加成功",
            "keyword": keyword,
            "image_url": image_url,
            "item_id": item_id or None
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"添加图片关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"添加图片关键词失败: {str(e)}")


@app.post("/upload-image")
async def upload_image(
    image: UploadFile = File(...),
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """上传图片（用于卡券等功能）"""
    try:
        logger.info(f"接收到图片上传请求: filename={image.filename}")

        # 验证图片文件
        if not image.content_type or not image.content_type.startswith('image/'):
            logger.warning(f"无效的图片文件类型: {image.content_type}")
            raise HTTPException(status_code=400, detail="请上传图片文件")

        # 读取图片数据
        image_data = await image.read()
        logger.info(f"读取图片数据成功，大小: {len(image_data)} bytes")

        # 保存图片
        image_url = image_manager.save_image(image_data, image.filename)
        if not image_url:
            logger.error("图片保存失败")
            raise HTTPException(status_code=400, detail="图片保存失败")

        logger.info(f"图片上传成功: {image_url}")

        return {
            "message": "图片上传成功",
            "image_url": image_url
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"图片上传失败: {e}")
        raise HTTPException(status_code=500, detail=f"图片上传失败: {str(e)}")


@app.get("/keywords-with-type/{cid}")
def get_keywords_with_type(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取包含类型信息的关键词列表"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    cookie_details = db_manager.get_cookie_details(cid)
    if not cookie_details or cookie_details['user_id'] != current_user['user_id']:
        raise HTTPException(status_code=404, detail="账号不存在或无权限")

    try:
        keywords = db_manager.get_keywords_with_type(cid)
        return keywords
    except Exception as e:
        logger.error(f"获取关键词列表失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取关键词列表失败: {str(e)}")


@app.delete("/keywords/{cid}/{index}")
def delete_keyword_by_index(cid: str, index: int, current_user: Dict[str, Any] = Depends(get_current_user)):
    """根据索引删除关键词"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    cookie_details = db_manager.get_cookie_details(cid)
    if not cookie_details or cookie_details['user_id'] != current_user['user_id']:
        raise HTTPException(status_code=404, detail="账号不存在或无权限")

    try:
        # 先获取要删除的关键词信息（用于删除图片文件）
        keywords = db_manager.get_keywords_with_type(cid)
        if 0 <= index < len(keywords):
            keyword_data = keywords[index]

            # 删除关键词
            success = db_manager.delete_keyword_by_index(cid, index)
            if not success:
                raise HTTPException(status_code=400, detail="删除关键词失败")

            # 如果是图片关键词，删除对应的图片文件
            if keyword_data.get('type') == 'image' and keyword_data.get('image_url'):
                image_manager.delete_image(keyword_data['image_url'])

            log_with_user('info', f"删除关键词成功: {cid}, 索引: {index}, 关键词: {keyword_data.get('keyword')}", current_user)

            return {"msg": "删除成功"}
        else:
            raise HTTPException(status_code=400, detail="关键词索引无效")

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"删除关键词失败: {str(e)}")


@app.delete("/keywords/{cid}/item/{item_id}")
def delete_keywords_by_item_id(cid: str, item_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """删除指定商品ID的所有关键词"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    cookie_details = db_manager.get_cookie_details(cid)
    if not cookie_details or cookie_details['user_id'] != current_user['user_id']:
        raise HTTPException(status_code=404, detail="账号不存在或无权限")

    try:
        # 先获取要删除的关键词信息（用于删除图片文件）
        keywords = db_manager.get_keywords_with_type(cid)
        keywords_to_delete = [k for k in keywords if k.get('item_id') == item_id]
        
        if not keywords_to_delete:
            raise HTTPException(status_code=404, detail=f"没有找到商品ID {item_id} 的关键词")

        # 删除关键词
        success = db_manager.delete_keywords_by_item_id(cid, item_id)
        if not success:
            raise HTTPException(status_code=400, detail="删除商品关键词失败")

        # 删除图片文件
        for keyword_data in keywords_to_delete:
            if keyword_data.get('type') == 'image' and keyword_data.get('image_url'):
                image_manager.delete_image(keyword_data['image_url'])

        log_with_user('info', f"删除商品ID {item_id} 的所有关键词成功: {cid}, 共删除 {len(keywords_to_delete)} 个关键词", current_user)

        return {"msg": f"删除成功，共删除 {len(keywords_to_delete)} 个关键词"}

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除商品关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"删除商品关键词失败: {str(e)}")


@app.get("/debug/keywords-table-info")
def debug_keywords_table_info(current_user: Dict[str, Any] = Depends(get_current_user)):
    """调试：检查keywords表结构"""
    try:
        import sqlite3
        conn = sqlite3.connect(db_manager.db_path)
        cursor = conn.cursor()

        # 获取表结构信息
        cursor.execute("PRAGMA table_info(keywords)")
        columns = cursor.fetchall()

        # 获取数据库版本
        cursor.execute("SELECT value FROM system_settings WHERE key = 'db_version'")
        version_result = cursor.fetchone()
        db_version = version_result[0] if version_result else "未知"

        conn.close()

        return {
            "db_version": db_version,
            "table_columns": [{"name": col[1], "type": col[2], "default": col[4]} for col in columns]
        }
    except Exception as e:
        logger.error(f"检查表结构失败: {e}")
        raise HTTPException(status_code=500, detail=f"检查表结构失败: {str(e)}")


# 卡种管理API
@app.get("/cards")
def get_cards(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户的卡券列表"""
    try:
        from db_manager import db_manager
        user_id = current_user['user_id']
        cards = db_manager.get_all_cards(user_id)
        return cards
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/cards")
def create_card(card_data: dict, current_user: Dict[str, Any] = Depends(get_current_user)):
    """创建新卡券"""
    try:
        from db_manager import db_manager
        user_id = current_user['user_id']
        card_name = card_data.get('name', '未命名卡券')

        log_with_user('info', f"创建卡券: {card_name}", current_user)

        card_id = db_manager.create_card(
            name=card_data.get('name'),
            card_type=card_data.get('type'),
            api_config=card_data.get('api_config'),
            text_content=card_data.get('text_content'),
            data_content=card_data.get('data_content'),
            image_url=card_data.get('image_url'),
            description=card_data.get('description'),
            enabled=card_data.get('enabled', True),
            delay_seconds=card_data.get('delay_seconds', 0),
            user_id=user_id,
            stock_warning_threshold=card_data.get('stock_warning_threshold', 0)
        )

        log_with_user('info', f"卡券创建成功: {card_name} (ID: {card_id})", current_user)
        return {"id": card_id, "message": "卡券创建成功"}
    except Exception as e:
        log_with_user('error', f"创建卡券失败: {card_data.get('name', '未知')} - {str(e)}", current_user)
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/cards/{card_id}")
def get_card(card_id: int, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取单个卡券详情"""
    try:
        from db_manager import db_manager
        user_id = current_user['user_id']
        card = db_manager.get_card_by_id(card_id, user_id)
        if card:
            return card
        else:
            raise HTTPException(status_code=404, detail="卡券不存在")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.put("/cards/{card_id}")
def update_card(card_id: int, card_data: dict, _: None = Depends(require_auth)):
    """更新卡券"""
    try:
        from db_manager import db_manager
        success = db_manager.update_card(
            card_id=card_id,
            name=card_data.get('name'),
            card_type=card_data.get('type'),
            api_config=card_data.get('api_config'),
            text_content=card_data.get('text_content'),
            data_content=card_data.get('data_content'),
            image_url=card_data.get('image_url'),
            description=card_data.get('description'),
            enabled=card_data.get('enabled', True),
            delay_seconds=card_data.get('delay_seconds'),
            stock_warning_threshold=card_data.get('stock_warning_threshold')
        )
        if success:
            return {"message": "卡券更新成功"}
        else:
            raise HTTPException(status_code=404, detail="卡券不存在")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.put("/cards/{card_id}/image")
async def update_card_with_image(
    card_id: int,
    image: UploadFile = File(...),
    name: str = Form(...),
    type: str = Form(...),
    description: str = Form(default=""),
    delay_seconds: int = Form(default=0),
    enabled: bool = Form(default=True),

    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """更新带图片的卡券"""
    try:
        logger.info(f"接收到带图片的卡券更新请求: card_id={card_id}, name={name}, type={type}")

        # 验证图片文件
        if not image.content_type or not image.content_type.startswith('image/'):
            logger.warning(f"无效的图片文件类型: {image.content_type}")
            raise HTTPException(status_code=400, detail="请上传图片文件")

        # 读取图片数据
        image_data = await image.read()
        logger.info(f"读取图片数据成功，大小: {len(image_data)} bytes")

        # 保存图片
        image_url = image_manager.save_image(image_data, image.filename)
        if not image_url:
            logger.error("图片保存失败")
            raise HTTPException(status_code=400, detail="图片保存失败")

        logger.info(f"图片保存成功: {image_url}")

        # 更新卡券
        from db_manager import db_manager
        success = db_manager.update_card(
            card_id=card_id,
            name=name,
            card_type=type,
            image_url=image_url,
            description=description,
            enabled=enabled,
            delay_seconds=delay_seconds
        )

        if success:
            logger.info(f"卡券更新成功: {name} (ID: {card_id})")
            return {"message": "卡券更新成功", "image_url": image_url}
        else:
            # 如果数据库更新失败，删除已保存的图片
            image_manager.delete_image(image_url)
            raise HTTPException(status_code=404, detail="卡券不存在")

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"更新带图片的卡券失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


# 自动发货规则API
@app.get("/delivery-rules")
def get_delivery_rules(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取发货规则列表"""
    try:
        from db_manager import db_manager
        user_id = current_user['user_id']
        rules = db_manager.get_all_delivery_rules(user_id)
        return rules
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/delivery-rules")
def create_delivery_rule(rule_data: dict, current_user: Dict[str, Any] = Depends(get_current_user)):
    """创建新发货规则"""
    try:
        from db_manager import db_manager
        user_id = current_user['user_id']
        
        # 记录请求数据用于调试
        logger.info(f"创建发货规则请求: user_id={user_id}, rule_data={rule_data}")
        
        # 获取商品ID，支持多种格式
        item_ids = []
        
        # 支持新格式：item_ids 数组
        if 'item_ids' in rule_data and rule_data['item_ids']:
            if isinstance(rule_data['item_ids'], list):
                item_ids = [str(item_id).strip() for item_id in rule_data['item_ids'] if str(item_id).strip()]
            else:
                item_ids = [str(rule_data['item_ids']).strip()]
        
        # 支持旧格式：item_id 字符串（逗号或换行分隔）
        elif 'item_id' in rule_data and rule_data['item_id']:
            item_ids_str = str(rule_data['item_id']).strip()
            # 先按换行分割，再按逗号分割，支持混合使用
            for line in item_ids_str.split('\n'):
                line = line.strip()
                if line:
                    # 每行可能包含逗号分隔的多个ID
                    line_ids = [item_id.strip() for item_id in line.split(',') if item_id.strip()]
                    item_ids.extend(line_ids)
        
        if not item_ids:
            raise HTTPException(status_code=400, detail="商品ID不能为空")
        
        # 去重并保持顺序
        item_ids = list(dict.fromkeys(item_ids))  # 保持顺序的去重
        
        # 为每个商品ID创建发货规则
        created_rules = []
        for item_id in item_ids:
            # 检查是否已存在相同的规则
            existing_rules = db_manager.get_delivery_rules_by_item_id(item_id, user_id)
            card_id = rule_data.get('card_id')
            
            # 检查是否已存在相同商品ID和卡券ID的规则
            rule_exists = any(rule['card_id'] == card_id for rule in existing_rules)
            if rule_exists:
                continue  # 跳过已存在的规则
            
            rule_id = db_manager.create_delivery_rule(
                item_id=item_id,
                card_id=card_id,
                delivery_count=rule_data.get('delivery_count', 1),
                enabled=rule_data.get('enabled', True),
                description=rule_data.get('description'),
                generate_image=rule_data.get('generate_image', True),
                is_multi_spec=rule_data.get('is_multi_spec', False),
                spec_name=rule_data.get('spec_name'),
                spec_value=rule_data.get('spec_value'),
                user_id=user_id
            )
            created_rules.append({"item_id": item_id, "rule_id": rule_id})
        
        if not created_rules:
            return {"message": "所有规则都已存在，未创建新规则", "created_count": 0}
        
        return {
            "message": f"成功创建 {len(created_rules)} 条发货规则",
            "created_count": len(created_rules),
            "created_rules": created_rules
        }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"创建发货规则失败: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"创建发货规则失败: {str(e)}")


@app.get("/delivery-rules/{rule_id}")
def get_delivery_rule(rule_id: int, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取单个发货规则详情"""
    try:
        from db_manager import db_manager
        user_id = current_user['user_id']
        rule = db_manager.get_delivery_rule_by_id(rule_id, user_id)
        if rule:
            return rule
        else:
            raise HTTPException(status_code=404, detail="发货规则不存在")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.put("/delivery-rules/{rule_id}")
def update_delivery_rule(rule_id: int, rule_data: dict, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新发货规则"""
    try:
        from db_manager import db_manager
        user_id = current_user['user_id']
        success = db_manager.update_delivery_rule(
            rule_id=rule_id,
            item_id=rule_data.get('item_id'),
            card_id=rule_data.get('card_id'),
            delivery_count=rule_data.get('delivery_count'),
            enabled=rule_data.get('enabled'),
            description=rule_data.get('description'),
            generate_image=rule_data.get('generate_image'),
            is_multi_spec=rule_data.get('is_multi_spec'),
            spec_name=rule_data.get('spec_name'),
            spec_value=rule_data.get('spec_value')
        )
        if success:
            return {"message": "发货规则更新成功"}
        else:
            raise HTTPException(status_code=404, detail="发货规则不存在")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.delete("/cards/{card_id}")
def delete_card(card_id: int, _: None = Depends(require_auth)):
    """删除卡券"""
    try:
        from db_manager import db_manager
        success = db_manager.delete_card(card_id)
        if success:
            return {"message": "卡券删除成功"}
        else:
            raise HTTPException(status_code=404, detail="卡券不存在")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.delete("/delivery-rules/{rule_id}")
def delete_delivery_rule(rule_id: int, current_user: Dict[str, Any] = Depends(get_current_user)):
    """删除发货规则"""
    try:
        from db_manager import db_manager
        user_id = current_user['user_id']
        success = db_manager.delete_delivery_rule(rule_id, user_id)
        if success:
            return {"message": "发货规则删除成功"}
        else:
            raise HTTPException(status_code=404, detail="发货规则不存在")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ==================== 备份和恢复 API ====================

@app.get("/backup/export")
def export_backup(current_user: Dict[str, Any] = Depends(get_current_user)):
    """导出用户备份"""
    try:
        from db_manager import db_manager
        user_id = current_user['user_id']
        username = current_user['username']

        # 导出当前用户的数据
        backup_data = db_manager.export_backup(user_id)

        # 生成文件名
        import datetime
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"xianyu_backup_{username}_{timestamp}.json"

        # 返回JSON响应，设置下载头
        response = JSONResponse(content=backup_data)
        response.headers["Content-Disposition"] = f"attachment; filename={filename}"
        response.headers["Content-Type"] = "application/json"

        return response
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"导出备份失败: {str(e)}")


@app.post("/backup/import")
def import_backup(file: UploadFile = File(...), current_user: Dict[str, Any] = Depends(get_current_user)):
    """导入用户备份"""
    try:
        # 验证文件类型
        if not file.filename.endswith('.json'):
            raise HTTPException(status_code=400, detail="只支持JSON格式的备份文件")

        # 读取文件内容
        content = file.file.read()
        backup_data = json.loads(content.decode('utf-8'))

        # 导入备份到当前用户
        from db_manager import db_manager
        user_id = current_user['user_id']
        success = db_manager.import_backup(backup_data, user_id)

        if success:
            # 备份导入成功后，刷新 CookieManager 的内存缓存
            import cookie_manager
            if cookie_manager.manager:
                try:
                    cookie_manager.manager.reload_from_db()
                    logger.info("备份导入后已刷新 CookieManager 缓存")
                except Exception as e:
                    logger.error(f"刷新 CookieManager 缓存失败: {e}")

            return {"message": "备份导入成功"}
        else:
            raise HTTPException(status_code=400, detail="备份导入失败")

    except json.JSONDecodeError:
        raise HTTPException(status_code=400, detail="备份文件格式无效")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"导入备份失败: {str(e)}")


@app.post("/system/reload-cache")
def reload_cache(_: None = Depends(require_auth)):
    """重新加载系统缓存（用于手动刷新数据）"""
    try:
        import cookie_manager
        if cookie_manager.manager:
            success = cookie_manager.manager.reload_from_db()
            if success:
                return {"message": "系统缓存已刷新", "success": True}
            else:
                raise HTTPException(status_code=500, detail="缓存刷新失败")
        else:
            raise HTTPException(status_code=500, detail="CookieManager 未初始化")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"刷新缓存失败: {str(e)}")


# ==================== 商品管理 API ====================

@app.get("/items")
def get_all_items(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户的所有商品信息"""
    try:
        # 只返回当前用户的商品信息
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        all_items = []
        for cookie_id in user_cookies.keys():
            items = db_manager.get_items_by_cookie(cookie_id)
            all_items.extend(items)

        return {"items": all_items}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取商品信息失败: {str(e)}")


@app.get("/items/cookie/{cookie_id}")
def get_items_by_cookie(cookie_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取指定Cookie的商品信息"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        items = db_manager.get_items_by_cookie(cookie_id)
        return {"items": items}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取商品信息失败: {str(e)}")


@app.get("/items/{cookie_id}/{item_id}")
def get_item_detail(cookie_id: str, item_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取商品详情"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        item = db_manager.get_item_info(cookie_id, item_id)
        if not item:
            raise HTTPException(status_code=404, detail="商品不存在")
        return {"item": item}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取商品详情失败: {str(e)}")


class ItemDetailUpdate(BaseModel):
    item_detail: str


@app.put("/items/{cookie_id}/{item_id}")
def update_item_detail(
    cookie_id: str,
    item_id: str,
    update_data: ItemDetailUpdate,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """更新商品详情"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        success = db_manager.update_item_detail(cookie_id, item_id, update_data.item_detail)
        if success:
            return {"message": "商品详情更新成功"}
        else:
            raise HTTPException(status_code=400, detail="更新失败")
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"更新商品详情失败: {str(e)}")


@app.delete("/items/{cookie_id}/{item_id}")
def delete_item_info(
    cookie_id: str,
    item_id: str,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """删除商品信息"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        success = db_manager.delete_item_info(cookie_id, item_id)
        if success:
            return {"message": "商品信息删除成功"}
        else:
            raise HTTPException(status_code=404, detail="商品信息不存在")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除商品信息异常: {e}")
        raise HTTPException(status_code=500, detail=f"服务器错误: {str(e)}")


class BatchDeleteRequest(BaseModel):
    items: List[dict]  # [{"cookie_id": "xxx", "item_id": "yyy"}, ...]


class AIReplySettings(BaseModel):
    ai_enabled: bool
    model_name: str = "qwen-plus"
    api_key: str = ""
    base_url: str = "https://dashscope.aliyuncs.com/compatible-mode/v1"
    max_discount_percent: int = 10
    max_discount_amount: int = 100
    max_bargain_rounds: int = 3
    custom_prompts: str = ""


@app.delete("/items/batch")
def batch_delete_items(
    request: BatchDeleteRequest,
    _: None = Depends(require_auth)
):
    """批量删除商品信息"""
    try:
        if not request.items:
            raise HTTPException(status_code=400, detail="删除列表不能为空")

        success_count = db_manager.batch_delete_item_info(request.items)
        total_count = len(request.items)

        return {
            "message": f"批量删除完成",
            "success_count": success_count,
            "total_count": total_count,
            "failed_count": total_count - success_count
        }
    except Exception as e:
        logger.error(f"批量删除商品信息异常: {e}")
        raise HTTPException(status_code=500, detail=f"服务器错误: {str(e)}")


# ==================== AI回复管理API ====================

@app.get("/ai-reply-settings/{cookie_id}")
def get_ai_reply_settings(cookie_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取指定账号的AI回复设置"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        settings = db_manager.get_ai_reply_settings(cookie_id)
        return settings
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取AI回复设置异常: {e}")
        raise HTTPException(status_code=500, detail=f"服务器错误: {str(e)}")


@app.put("/ai-reply-settings/{cookie_id}")
def update_ai_reply_settings(cookie_id: str, settings: AIReplySettings, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新指定账号的AI回复设置"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")

        # 检查账号是否存在
        if cookie_manager.manager is None:
            raise HTTPException(status_code=500, detail='CookieManager 未就绪')

        # 保存设置
        settings_dict = settings.dict()
        success = db_manager.save_ai_reply_settings(cookie_id, settings_dict)

        if success:
            # 清理客户端缓存，强制重新创建
            ai_reply_engine.clear_client_cache(cookie_id)

            # 如果启用了AI回复，记录日志
            if settings.ai_enabled:
                logger.info(f"账号 {cookie_id} 启用AI回复")
            else:
                logger.info(f"账号 {cookie_id} 禁用AI回复")

            return {"message": "AI回复设置更新成功"}
        else:
            raise HTTPException(status_code=400, detail="更新失败")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"更新AI回复设置异常: {e}")
        raise HTTPException(status_code=500, detail=f"服务器错误: {str(e)}")


@app.get("/ai-reply-settings")
def get_all_ai_reply_settings(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户所有账号的AI回复设置"""
    try:
        # 只返回当前用户的AI回复设置
        user_id = current_user['user_id']
        from db_manager import db_manager
        user_cookies = db_manager.get_all_cookies(user_id)

        all_settings = db_manager.get_all_ai_reply_settings()
        # 过滤只属于当前用户的设置
        user_settings = {cid: settings for cid, settings in all_settings.items() if cid in user_cookies}
        return user_settings
    except Exception as e:
        logger.error(f"获取所有AI回复设置异常: {e}")
        raise HTTPException(status_code=500, detail=f"服务器错误: {str(e)}")


@app.post("/ai-reply-test/{cookie_id}")
def test_ai_reply(cookie_id: str, test_data: dict, _: None = Depends(require_auth)):
    """测试AI回复功能"""
    try:
        # 检查账号是否存在
        if cookie_manager.manager is None:
            raise HTTPException(status_code=500, detail='CookieManager 未就绪')

        if cookie_id not in cookie_manager.manager.cookies:
            raise HTTPException(status_code=404, detail='账号不存在')

        # 检查是否启用AI回复
        if not ai_reply_engine.is_ai_enabled(cookie_id):
            raise HTTPException(status_code=400, detail='该账号未启用AI回复')

        # 构造测试数据
        test_message = test_data.get('message', '你好')
        test_item_info = {
            'title': test_data.get('item_title', '测试商品'),
            'price': test_data.get('item_price', 100),
            'desc': test_data.get('item_desc', '这是一个测试商品')
        }

        # 生成测试回复
        reply = ai_reply_engine.generate_reply(
            message=test_message,
            item_info=test_item_info,
            chat_id=f"test_{int(time.time())}",
            cookie_id=cookie_id,
            user_id="test_user",
            item_id="test_item"
        )

        if reply:
            return {"message": "测试成功", "reply": reply}
        else:
            raise HTTPException(status_code=400, detail="AI回复生成失败")

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"测试AI回复异常: {e}")
        raise HTTPException(status_code=500, detail=f"服务器错误: {str(e)}")


# ==================== 日志管理API ====================

@app.get("/logs")
async def get_logs(lines: int = 200, level: str = None, source: str = None, _: None = Depends(require_auth)):
    """获取实时系统日志"""
    try:
        # 获取文件日志收集器
        collector = get_file_log_collector()

        # 获取日志
        logs = collector.get_logs(lines=lines, level_filter=level, source_filter=source)

        return {"success": True, "logs": logs}

    except Exception as e:
        return {"success": False, "message": f"获取日志失败: {str(e)}", "logs": []}


@app.get("/logs/stats")
async def get_log_stats(_: None = Depends(require_auth)):
    """获取日志统计信息"""
    try:
        collector = get_file_log_collector()
        stats = collector.get_stats()

        return {"success": True, "stats": stats}

    except Exception as e:
        return {"success": False, "message": f"获取日志统计失败: {str(e)}", "stats": {}}


@app.post("/logs/clear")
async def clear_logs(_: None = Depends(require_auth)):
    """清空日志"""
    try:
        collector = get_file_log_collector()
        collector.clear_logs()

        return {"success": True, "message": "日志已清空"}

    except Exception as e:
        return {"success": False, "message": f"清空日志失败: {str(e)}"}


# ==================== 商品管理API ====================

@app.post("/items/get-all-from-account")
async def get_all_items_from_account(request: dict, _: None = Depends(require_auth)):
    """从指定账号获取所有商品信息"""
    try:
        cookie_id = request.get('cookie_id')
        if not cookie_id:
            return {"success": False, "message": "缺少cookie_id参数"}

        # 获取指定账号的cookie信息
        cookie_info = db_manager.get_cookie_by_id(cookie_id)
        if not cookie_info:
            return {"success": False, "message": "未找到指定的账号信息"}

        cookies_str = cookie_info.get('value', '')
        if not cookies_str:
            return {"success": False, "message": "账号cookie信息为空"}

        # 创建XianyuLive实例，传入正确的cookie_id
        from XianyuAutoAsync import XianyuLive
        xianyu_instance = XianyuLive(cookies_str, cookie_id)

        # 调用获取所有商品信息的方法（自动分页）
        logger.info(f"开始获取账号 {cookie_id} 的所有商品信息")
        result = await xianyu_instance.get_all_items()

        # 关闭session
        await xianyu_instance.close_session()

        if result.get('error'):
            logger.error(f"获取商品信息失败: {result['error']}")
            return {"success": False, "message": result['error']}
        else:
            total_count = result.get('total_count', 0)
            total_pages = result.get('total_pages', 1)
            logger.info(f"成功获取账号 {cookie_id} 的 {total_count} 个商品（共{total_pages}页）")
            return {
                "success": True,
                "message": f"成功获取 {total_count} 个商品（共{total_pages}页），详细信息已打印到控制台",
                "total_count": total_count,
                "total_pages": total_pages
            }

    except Exception as e:
        logger.error(f"获取账号商品信息异常: {str(e)}")
        return {"success": False, "message": f"获取商品信息异常: {str(e)}"}


@app.post("/items/get-by-page")
async def get_items_by_page(request: dict, _: None = Depends(require_auth)):
    """从指定账号按页获取商品信息"""
    try:
        # 验证参数
        cookie_id = request.get('cookie_id')
        page_number = request.get('page_number', 1)
        page_size = request.get('page_size', 20)

        if not cookie_id:
            return {"success": False, "message": "缺少cookie_id参数"}

        # 验证分页参数
        try:
            page_number = int(page_number)
            page_size = int(page_size)
        except (ValueError, TypeError):
            return {"success": False, "message": "页码和每页数量必须是数字"}

        if page_number < 1:
            return {"success": False, "message": "页码必须大于0"}

        if page_size < 1 or page_size > 100:
            return {"success": False, "message": "每页数量必须在1-100之间"}

        # 获取账号信息
        account = db_manager.get_cookie_by_id(cookie_id)
        if not account:
            return {"success": False, "message": "账号不存在"}

        cookies_str = account['value']
        if not cookies_str:
            return {"success": False, "message": "账号cookies为空"}

        # 创建XianyuLive实例，传入正确的cookie_id
        from XianyuAutoAsync import XianyuLive
        xianyu_instance = XianyuLive(cookies_str, cookie_id)

        # 调用获取指定页商品信息的方法
        logger.info(f"开始获取账号 {cookie_id} 第{page_number}页商品信息（每页{page_size}条）")
        result = await xianyu_instance.get_item_list_info(page_number, page_size)

        # 关闭session
        await xianyu_instance.close_session()

        if result.get('error'):
            logger.error(f"获取商品信息失败: {result['error']}")
            return {"success": False, "message": result['error']}
        else:
            current_count = result.get('current_count', 0)
            logger.info(f"成功获取账号 {cookie_id} 第{page_number}页 {current_count} 个商品")
            return {
                "success": True,
                "message": f"成功获取第{page_number}页 {current_count} 个商品，详细信息已打印到控制台",
                "page_number": page_number,
                "page_size": page_size,
                "current_count": current_count
            }

    except Exception as e:
        logger.error(f"获取账号商品信息异常: {str(e)}")
        return {"success": False, "message": f"获取商品信息异常: {str(e)}"}


# ------------------------- 用户设置接口 -------------------------

@app.get('/user-settings')
def get_user_settings(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户的设置"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        settings = db_manager.get_user_settings(user_id)
        return settings
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.put('/user-settings/{key}')
def update_user_setting(key: str, setting_data: dict, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新用户设置"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        value = setting_data.get('value')
        description = setting_data.get('description', '')

        log_with_user('info', f"更新用户设置: {key} = {value}", current_user)

        success = db_manager.set_user_setting(user_id, key, value, description)
        if success:
            log_with_user('info', f"用户设置更新成功: {key}", current_user)
            return {'msg': 'setting updated', 'key': key, 'value': value}
        else:
            log_with_user('error', f"用户设置更新失败: {key}", current_user)
            raise HTTPException(status_code=400, detail='更新失败')
    except Exception as e:
        log_with_user('error', f"更新用户设置异常: {key} - {str(e)}", current_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/user-settings/{key}')
def get_user_setting(key: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取用户特定设置"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        setting = db_manager.get_user_setting(user_id, key)
        if setting:
            return setting
        else:
            raise HTTPException(status_code=404, detail='设置不存在')
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ------------------------- 个人信息接口 -------------------------

@app.get('/current-user')
def get_current_user_info(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户信息"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        user_info = db_manager.get_user_by_id(user_id)
        
        if user_info:
            # 移除敏感信息
            if 'password_hash' in user_info:
                del user_info['password_hash']
            
            # 获取用户聚合豆余额
            balance = db_manager.get_user_balance(user_id)
            user_info['balance'] = balance
            
            # 初始化余额（如果不存在）
            if balance == 0.0:
                db_manager.init_user_balance(user_id)
            
            return user_info
        else:
            raise HTTPException(status_code=404, detail='用户不存在')
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.put('/user-info')
def update_user_info(user_data: dict, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新用户基本信息"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        
        # 验证邮箱格式
        email = user_data.get('email', '').strip()
        if not email:
            raise HTTPException(status_code=400, detail='邮箱地址不能为空')
        
        # 检查邮箱是否已被其他用户使用
        existing_user = db_manager.get_user_by_email(email)
        if existing_user and existing_user['id'] != user_id:
            raise HTTPException(status_code=400, detail='该邮箱地址已被其他用户使用')
        
        # 更新用户信息
        success = db_manager.update_user_info(user_id, {
            'email': email,
            'phone': user_data.get('phone', '').strip(),
            'nickname': user_data.get('nickname', '').strip()
        })
        
        if success:
            log_with_user('info', f"用户信息更新成功", current_user)
            return {'success': True, 'message': '个人信息更新成功'}
        else:
            raise HTTPException(status_code=400, detail='更新失败')
    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"更新用户信息异常: {str(e)}", current_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.post('/change-password')
def change_user_password(request: ChangePasswordRequest, current_user: Dict[str, Any] = Depends(get_current_user)):
    """修改当前用户密码"""
    from db_manager import db_manager
    try:
        username = current_user['username']
        
        # 验证当前密码
        if not db_manager.verify_user_password(username, request.current_password):
            return {"success": False, "message": "当前密码错误"}
        
        # 更新密码
        success = db_manager.update_user_password(username, request.new_password)
        
        if success:
            log_with_user('info', f"用户密码修改成功", current_user)
            return {"success": True, "message": "密码修改成功"}
        else:
            return {"success": False, "message": "密码修改失败"}
    except Exception as e:
        log_with_user('error', f"修改用户密码异常: {str(e)}", current_user)
        return {"success": False, "message": "系统错误"}

# ------------------------- 聚合豆管理接口 -------------------------

@app.get('/user-balance')
def get_user_balance(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户聚合豆余额"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        balance = db_manager.get_user_balance(user_id)
        
        # 初始化余额（如果不存在）
        if balance == 0.0:
            db_manager.init_user_balance(user_id)
        
        return {
            'success': True,
            'balance': balance
        }
    except Exception as e:
        logger.error(f"获取用户余额失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/balance-records')
def get_balance_records(
    page: int = 1,
    page_size: int = 20,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """获取当前用户的聚合豆消费记录"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        result = db_manager.get_balance_records(user_id, page, page_size)
        return {
            'success': True,
            'data': result
        }
    except Exception as e:
        logger.error(f"获取余额记录失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))

class BalanceAdjustRequest(BaseModel):
    user_id: int
    operation: str  # 'add' 或 'subtract'
    amount: float
    reason: str = ""

@app.post('/admin/adjust-balance')
def admin_adjust_user_balance(
    request: BalanceAdjustRequest,
    admin_user: Dict[str, Any] = Depends(require_admin)
):
    """管理员调整用户聚合豆余额"""
    from db_manager import db_manager
    try:
        admin_user_id = admin_user['user_id']
        
        # 验证参数
        if not request.operation or request.operation not in ['add', 'subtract']:
            raise HTTPException(status_code=400, detail="无效的操作类型")
        
        if request.amount <= 0:
            raise HTTPException(status_code=400, detail="金额必须大于0")
        
        # 验证目标用户是否存在
        target_user = db_manager.get_user_by_id(request.user_id)
        if not target_user:
            raise HTTPException(status_code=404, detail="目标用户不存在")
        
        # 初始化用户余额（如果不存在）
        db_manager.init_user_balance(request.user_id)
        
        # 根据操作类型计算实际调整金额
        if request.operation == 'subtract':
            # 扣除操作，金额为负数
            actual_amount = -request.amount
        else:
            # 充值操作，金额为正数
            actual_amount = request.amount
        
        # 调整余额
        success = db_manager.admin_adjust_balance(
            user_id=request.user_id,
            amount=actual_amount,
            description=request.reason,
            admin_user_id=admin_user_id
        )
        
        if success:
            action = "充值" if request.operation == 'add' else "扣除"
            log_with_user('info', f"管理员{action}用户余额: 目标用户ID={request.user_id}, 金额={request.amount}, 描述={request.reason}", admin_user)
            
            # 获取调整后的余额
            new_balance = db_manager.get_user_balance(request.user_id)
            
            return {
                'success': True,
                'message': f"余额{action}成功",
                'new_balance': new_balance
            }
        else:
            return {
                'success': False,
                'message': "余额不足或操作失败"
            }
    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"管理员调整余额失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/admin/user/{user_id}/balance')
def get_user_balance_admin(
    user_id: int,
    admin_user: Dict[str, Any] = Depends(require_admin)
):
    """管理员查看指定用户的聚合豆余额和记录"""
    from db_manager import db_manager
    try:
        # 验证目标用户是否存在
        target_user = db_manager.get_user_by_id(user_id)
        if not target_user:
            raise HTTPException(status_code=404, detail="目标用户不存在")
        
        # 获取余额
        balance = db_manager.get_user_balance(user_id)
        
        # 获取最近的记录
        records_result = db_manager.get_balance_records(user_id, 1, 10)
        
        log_with_user('info', f"管理员查看用户余额: 目标用户ID={user_id}", admin_user)
        
        return {
            'success': True,
            'user_info': {
                'id': target_user['id'],
                'username': target_user['username'],
                'email': target_user['email']
            },
            'balance': balance,
            'recent_records': records_result['records']
        }
    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"管理员查看用户余额失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/admin/user-balance/{user_id}')
def get_user_balance_admin(user_id: int, admin_user: Dict[str, Any] = Depends(require_admin)):
    """管理员获取用户聚合豆余额"""
    from db_manager import db_manager
    try:
        balance = db_manager.get_user_balance(user_id)
        
        # 初始化余额（如果不存在）
        if balance == 0.0:
            db_manager.init_user_balance(user_id)
            
        return {
            'success': True,
            'balance': balance
        }
    except Exception as e:
        logger.error(f"管理员获取用户余额失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))



# ------------------------- 管理员专用接口 -------------------------

@app.get('/admin/users')
def get_all_users(admin_user: Dict[str, Any] = Depends(require_admin)):
    """获取所有用户信息（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', "查询所有用户信息", admin_user)
        users = db_manager.get_all_users()

        # 为每个用户添加统计信息
        for user in users:
            user_id = user['id']
            # 统计用户的Cookie数量
            user_cookies = db_manager.get_all_cookies(user_id)
            user['cookie_count'] = len(user_cookies)

            # 统计用户的卡券数量
            user_cards = db_manager.get_all_cards(user_id)
            user['card_count'] = len(user_cards) if user_cards else 0
            
            # 获取用户角色信息
            user_roles = db_manager.get_user_roles(user_id)
            user['roles'] = user_roles

            # 隐藏密码字段
            if 'password_hash' in user:
                del user['password_hash']

        log_with_user('info', f"返回用户信息，共 {len(users)} 个用户", admin_user)
        return {"users": users}
    except Exception as e:
        log_with_user('error', f"获取用户信息失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.delete('/admin/users/{user_id}')
def delete_user(user_id: int, admin_user: Dict[str, Any] = Depends(require_admin)):
    """删除用户（管理员专用）"""
    from db_manager import db_manager
    try:
        # 不能删除管理员自己
        if user_id == admin_user['user_id']:
            log_with_user('warning', "尝试删除管理员自己", admin_user)
            raise HTTPException(status_code=400, detail="不能删除管理员自己")

        # 获取要删除的用户信息
        user_to_delete = db_manager.get_user_by_id(user_id)
        if not user_to_delete:
            raise HTTPException(status_code=404, detail="用户不存在")

        log_with_user('info', f"准备删除用户: {user_to_delete['username']} (ID: {user_id})", admin_user)

        # 删除用户及其相关数据
        success = db_manager.delete_user_and_data(user_id)

        if success:
            log_with_user('info', f"用户删除成功: {user_to_delete['username']} (ID: {user_id})", admin_user)
            return {"message": f"用户 {user_to_delete['username']} 删除成功"}
        else:
            log_with_user('error', f"用户删除失败: {user_to_delete['username']} (ID: {user_id})", admin_user)
            raise HTTPException(status_code=400, detail="删除失败")
    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"删除用户异常: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.post('/admin/users')
def create_user_admin(request: AdminUserCreateRequest, admin_user: Dict[str, Any] = Depends(require_admin)):
    """创建用户（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', f"管理员创建用户: {request.username}", admin_user)
        
        # 检查用户名是否已存在
        existing_user = db_manager.get_user_by_username(request.username)
        if existing_user:
            log_with_user('warning', f"用户创建失败: 用户名已存在 - {request.username}", admin_user)
            return {
                "success": False,
                "message": "用户名已存在"
            }

        # 检查邮箱是否已注册
        existing_email = db_manager.get_user_by_email(request.email)
        if existing_email:
            log_with_user('warning', f"用户创建失败: 邮箱已被注册 - {request.email}", admin_user)
            return {
                "success": False,
                "message": "该邮箱已被注册"
            }

        # 创建用户（绕过邮箱验证）
        if db_manager.create_user(request.username, request.email, request.password):
            log_with_user('info', f"管理员成功创建用户: {request.username}", admin_user)
            
            # 获取新创建的用户信息
            new_user = db_manager.get_user_by_username(request.username)
            if new_user:
                # 隐藏密码字段
                if 'password_hash' in new_user:
                    del new_user['password_hash']
                new_user['cookie_count'] = 0
                new_user['card_count'] = 0
                
            return {
                "success": True,
                "message": "用户创建成功",
                "user": new_user
            }
        else:
            log_with_user('error', f"用户创建失败: 数据库操作失败 - {request.username}", admin_user)
            return {
                "success": False,
                "message": "用户创建失败"
            }
            
    except Exception as e:
        log_with_user('error', f"创建用户异常: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/admin/logs')
def get_system_logs(admin_user: Dict[str, Any] = Depends(require_admin),
                   lines: int = 100,
                   level: str = None):
    """获取系统日志（管理员专用）"""
    import os
    import glob
    from datetime import datetime

    try:
        log_with_user('info', f"查询系统日志，行数: {lines}, 级别: {level}", admin_user)

        # 查找日志文件
        log_files = glob.glob("logs/xianyu_*.log")
        if not log_files:
            return {"logs": [], "message": "未找到日志文件"}

        # 获取最新的日志文件
        latest_log_file = max(log_files, key=os.path.getctime)

        logs = []
        try:
            with open(latest_log_file, 'r', encoding='utf-8') as f:
                all_lines = f.readlines()

                # 如果指定了日志级别，进行过滤
                if level:
                    filtered_lines = [line for line in all_lines if f"| {level.upper()} |" in line]
                else:
                    filtered_lines = all_lines

                # 获取最后N行
                recent_lines = filtered_lines[-lines:] if len(filtered_lines) > lines else filtered_lines

                for line in recent_lines:
                    logs.append(line.strip())

        except Exception as e:
            log_with_user('error', f"读取日志文件失败: {str(e)}", admin_user)
            return {"logs": [], "message": f"读取日志文件失败: {str(e)}"}

        log_with_user('info', f"返回日志记录 {len(logs)} 条", admin_user)
        return {
            "logs": logs,
            "log_file": latest_log_file,
            "total_lines": len(logs)
        }

    except Exception as e:
        log_with_user('error', f"获取系统日志失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/admin/stats')
def get_system_stats(admin_user: Dict[str, Any] = Depends(require_admin)):
    """获取系统统计信息（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', "查询系统统计信息", admin_user)

        stats = {
            "users": {
                "total": 0,
                "active_today": 0
            },
            "cookies": {
                "total": 0,
                "enabled": 0
            },
            "cards": {
                "total": 0,
                "enabled": 0
            },
            "system": {
                "uptime": "未知",
                "version": "1.0.0"
            }
        }

        # 用户统计
        all_users = db_manager.get_all_users()
        stats["users"]["total"] = len(all_users)

        # Cookie统计
        all_cookies = db_manager.get_all_cookies()
        stats["cookies"]["total"] = len(all_cookies)

        # 卡券统计
        all_cards = db_manager.get_all_cards()
        if all_cards:
            stats["cards"]["total"] = len(all_cards)
            stats["cards"]["enabled"] = len([card for card in all_cards if card.get('enabled', True)])

        log_with_user('info', "系统统计信息查询完成", admin_user)
        return stats

    except Exception as e:
        log_with_user('error', f"获取系统统计信息失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))


# ------------------------- 数据库备份和恢复接口 -------------------------

@app.get('/admin/backup/download')
def download_database_backup(admin_user: Dict[str, Any] = Depends(require_admin)):
    """下载数据库备份文件（管理员专用）"""
    import os
    from fastapi.responses import FileResponse
    from datetime import datetime

    try:
        log_with_user('info', "请求下载数据库备份", admin_user)

        # 使用db_manager的实际数据库路径
        from db_manager import db_manager
        db_file_path = db_manager.db_path

        # 检查数据库文件是否存在
        if not os.path.exists(db_file_path):
            log_with_user('error', f"数据库文件不存在: {db_file_path}", admin_user)
            raise HTTPException(status_code=404, detail="数据库文件不存在")

        # 生成带时间戳的文件名
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        download_filename = f"xianyu_backup_{timestamp}.db"

        log_with_user('info', f"开始下载数据库备份: {download_filename}", admin_user)

        return FileResponse(
            path=db_file_path,
            filename=download_filename,
            media_type='application/octet-stream'
        )

    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"下载数据库备份失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.post('/admin/backup/upload')
async def upload_database_backup(admin_user: Dict[str, Any] = Depends(require_admin),
                                backup_file: UploadFile = File(...)):
    """上传并恢复数据库备份文件（管理员专用）"""
    import os
    import shutil
    import sqlite3
    from datetime import datetime

    try:
        log_with_user('info', f"开始上传数据库备份: {backup_file.filename}", admin_user)

        # 验证文件类型
        if not backup_file.filename.endswith('.db'):
            log_with_user('warning', f"无效的备份文件类型: {backup_file.filename}", admin_user)
            raise HTTPException(status_code=400, detail="只支持.db格式的数据库文件")

        # 验证文件大小（限制100MB）
        content = await backup_file.read()
        if len(content) > 100 * 1024 * 1024:  # 100MB
            log_with_user('warning', f"备份文件过大: {len(content)} bytes", admin_user)
            raise HTTPException(status_code=400, detail="备份文件大小不能超过100MB")

        # 验证是否为有效的SQLite数据库文件
        temp_file_path = f"temp_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.db"

        try:
            # 保存临时文件
            with open(temp_file_path, 'wb') as temp_file:
                temp_file.write(content)

            # 验证数据库文件完整性
            conn = sqlite3.connect(temp_file_path)
            cursor = conn.cursor()
            cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
            tables = cursor.fetchall()
            conn.close()

            # 检查是否包含必要的表
            table_names = [table[0] for table in tables]
            required_tables = ['users', 'cookies']  # 最基本的表

            missing_tables = [table for table in required_tables if table not in table_names]
            if missing_tables:
                log_with_user('warning', f"备份文件缺少必要的表: {missing_tables}", admin_user)
                raise HTTPException(status_code=400, detail=f"备份文件不完整，缺少表: {', '.join(missing_tables)}")

            log_with_user('info', f"备份文件验证通过，包含 {len(table_names)} 个表", admin_user)

        except sqlite3.Error as e:
            log_with_user('error', f"备份文件验证失败: {str(e)}", admin_user)
            if os.path.exists(temp_file_path):
                os.remove(temp_file_path)
            raise HTTPException(status_code=400, detail="无效的数据库文件")

        # 备份当前数据库
        from db_manager import db_manager
        current_db_path = db_manager.db_path

        # 生成备份文件路径（与原数据库在同一目录）
        db_dir = os.path.dirname(current_db_path)
        backup_filename = f"xianyu_data_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.db"
        backup_current_path = os.path.join(db_dir, backup_filename)

        if os.path.exists(current_db_path):
            shutil.copy2(current_db_path, backup_current_path)
            log_with_user('info', f"当前数据库已备份为: {backup_current_path}", admin_user)

        # 关闭当前数据库连接
        if hasattr(db_manager, 'conn') and db_manager.conn:
            db_manager.conn.close()
            log_with_user('info', "已关闭当前数据库连接", admin_user)

        # 替换数据库文件
        shutil.move(temp_file_path, current_db_path)
        log_with_user('info', f"数据库文件已替换: {current_db_path}", admin_user)

        # 重新初始化数据库连接（使用原有的db_path）
        db_manager.__init__(db_manager.db_path)
        log_with_user('info', "数据库连接已重新初始化", admin_user)

        # 验证新数据库
        try:
            test_users = db_manager.get_all_users()
            log_with_user('info', f"数据库恢复成功，包含 {len(test_users)} 个用户", admin_user)
        except Exception as e:
            log_with_user('error', f"数据库恢复后验证失败: {str(e)}", admin_user)
            # 如果验证失败，尝试恢复原数据库
            if os.path.exists(backup_current_path):
                shutil.copy2(backup_current_path, current_db_path)
                db_manager.__init__()
                log_with_user('info', "已恢复原数据库", admin_user)
            raise HTTPException(status_code=500, detail="数据库恢复失败，已回滚到原数据库")

        return {
            "success": True,
            "message": "数据库恢复成功",
            "backup_file": backup_current_path,
            "user_count": len(test_users)
        }

    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"上传数据库备份失败: {str(e)}", admin_user)
        # 清理临时文件
        if 'temp_file_path' in locals() and os.path.exists(temp_file_path):
            os.remove(temp_file_path)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/admin/backup/list')
def list_backup_files(admin_user: Dict[str, Any] = Depends(require_admin)):
    """列出服务器上的备份文件（管理员专用）"""
    import os
    import glob
    from datetime import datetime

    try:
        log_with_user('info', "查询备份文件列表", admin_user)

        # 查找备份文件
        backup_files = glob.glob("xianyu_data_backup_*.db")

        backup_list = []
        for file_path in backup_files:
            try:
                stat = os.stat(file_path)
                backup_list.append({
                    'filename': os.path.basename(file_path),
                    'size': stat.st_size,
                    'size_mb': round(stat.st_size / (1024 * 1024), 2),
                    'created_time': datetime.fromtimestamp(stat.st_ctime).strftime('%Y-%m-%d %H:%M:%S'),
                    'modified_time': datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S')
                })
            except Exception as e:
                log_with_user('warning', f"读取备份文件信息失败: {file_path} - {str(e)}", admin_user)

        # 按修改时间倒序排列
        backup_list.sort(key=lambda x: x['modified_time'], reverse=True)

        log_with_user('info', f"找到 {len(backup_list)} 个备份文件", admin_user)

        return {
            "backups": backup_list,
            "total": len(backup_list)
        }

    except Exception as e:
        log_with_user('error', f"查询备份文件列表失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))


# ------------------------- 数据管理接口 -------------------------

@app.get('/admin/data/{table_name}')
def get_table_data(table_name: str, admin_user: Dict[str, Any] = Depends(require_admin)):
    """获取指定表的所有数据（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', f"查询表数据: {table_name}", admin_user)

        # 验证表名安全性
        allowed_tables = [
            'users', 'cookies', 'cookie_status', 'keywords', 'default_replies', 'default_reply_records',
            'ai_reply_settings', 'ai_conversations', 'ai_item_cache', 'item_info',
            'message_notifications', 'cards', 'delivery_rules', 'notification_channels',
            'user_settings', 'system_settings', 'email_verifications', 'captcha_codes',
            'item_exclusive_replies', 'orders'
        ]

        if table_name not in allowed_tables:
            log_with_user('warning', f"尝试访问不允许的表: {table_name}", admin_user)
            raise HTTPException(status_code=400, detail="不允许访问该表")

        # 获取表数据
        data, columns = db_manager.get_table_data(table_name)

        log_with_user('info', f"表 {table_name} 查询成功，共 {len(data)} 条记录", admin_user)

        return {
            "success": True,
            "data": data,
            "columns": columns,
            "count": len(data)
        }

    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"查询表数据失败: {table_name} - {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.delete('/admin/data/{table_name}/{record_id}')
def delete_table_record(table_name: str, record_id: str, admin_user: Dict[str, Any] = Depends(require_admin)):
    """删除指定表的指定记录（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', f"删除表记录: {table_name}.{record_id}", admin_user)

        # 验证表名安全性
        allowed_tables = [
            'users', 'cookies', 'cookie_status', 'keywords', 'default_replies', 'default_reply_records',
            'ai_reply_settings', 'ai_conversations', 'ai_item_cache', 'item_info',
            'message_notifications', 'cards', 'delivery_rules', 'notification_channels',
            'user_settings', 'system_settings', 'email_verifications', 'captcha_codes',
            'item_exclusive_replies', 'orders'
        ]

        if table_name not in allowed_tables:
            log_with_user('warning', f"尝试删除不允许的表记录: {table_name}", admin_user)
            raise HTTPException(status_code=400, detail="不允许操作该表")

        # 特殊保护：不能删除管理员用户
        if table_name == 'users' and record_id == str(admin_user['user_id']):
            log_with_user('warning', "尝试删除管理员自己", admin_user)
            raise HTTPException(status_code=400, detail="不能删除管理员自己")

        # 删除记录
        success = db_manager.delete_table_record(table_name, record_id)

        if success:
            log_with_user('info', f"表记录删除成功: {table_name}.{record_id}", admin_user)
            return {"success": True, "message": "删除成功"}
        else:
            log_with_user('warning', f"表记录删除失败: {table_name}.{record_id}", admin_user)
            raise HTTPException(status_code=400, detail="删除失败，记录可能不存在")

    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"删除表记录异常: {table_name}.{record_id} - {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.delete('/admin/data/{table_name}')
def clear_table_data(table_name: str, admin_user: Dict[str, Any] = Depends(require_admin)):
    """清空指定表的所有数据（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', f"清空表数据: {table_name}", admin_user)

        # 验证表名安全性
        allowed_tables = [
            'cookies', 'cookie_status', 'keywords', 'default_replies', 'default_reply_records',
            'ai_reply_settings', 'ai_conversations', 'ai_item_cache', 'item_info',
            'message_notifications', 'cards', 'delivery_rules', 'notification_channels',
            'user_settings', 'system_settings', 'email_verifications', 'captcha_codes', 'orders'
        ]

        # 不允许清空用户表
        if table_name == 'users':
            log_with_user('warning', "尝试清空用户表", admin_user)
            raise HTTPException(status_code=400, detail="不允许清空用户表")

        if table_name not in allowed_tables:
            log_with_user('warning', f"尝试清空不允许的表: {table_name}", admin_user)
            raise HTTPException(status_code=400, detail="不允许清空该表")

        # 清空表数据
        success = db_manager.clear_table_data(table_name)

        if success:
            log_with_user('info', f"表数据清空成功: {table_name}", admin_user)
            return {"success": True, "message": "清空成功"}
        else:
            log_with_user('warning', f"表数据清空失败: {table_name}", admin_user)
            raise HTTPException(status_code=400, detail="清空失败")

    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"清空表数据异常: {table_name} - {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))


# 商品多规格管理API
@app.put("/items/{cookie_id}/{item_id}/multi-spec")
def update_item_multi_spec(cookie_id: str, item_id: str, spec_data: dict, _: None = Depends(require_auth)):
    """更新商品的多规格状态"""
    try:
        from db_manager import db_manager

        is_multi_spec = spec_data.get('is_multi_spec', False)

        success = db_manager.update_item_multi_spec_status(cookie_id, item_id, is_multi_spec)

        if success:
            return {"message": f"商品多规格状态已{'开启' if is_multi_spec else '关闭'}"}
        else:
            raise HTTPException(status_code=404, detail="商品不存在")

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# 移除自动启动，由Start.py或手动启动
# if __name__ == "__main__":
#     uvicorn.run(app, host="0.0.0.0", port=8080)


class CopyKeywordsRequest(BaseModel):
    source_item_id: str
    target_item_id: str


@app.post("/keywords/{cid}/copy")
def copy_keywords(cid: str, request: CopyKeywordsRequest, current_user: Dict[str, Any] = Depends(get_current_user)):
    """复制指定商品ID的关键词到另一个商品ID"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    cookie_details = db_manager.get_cookie_details(cid)
    if not cookie_details or cookie_details['user_id'] != current_user['user_id']:
        raise HTTPException(status_code=404, detail="账号不存在或无权限")

    try:
        # 获取源商品的关键词
        keywords = db_manager.get_keywords_with_type(cid)
        source_keywords = [k for k in keywords if k.get('item_id') == request.source_item_id]
        
        if not source_keywords:
            raise HTTPException(status_code=404, detail=f"没有找到商品ID {request.source_item_id} 的关键词")

        # 检查目标商品是否已有关键词
        target_keywords = [k for k in keywords if k.get('item_id') == request.target_item_id]
        if target_keywords:
            raise HTTPException(status_code=400, detail=f"目标商品ID {request.target_item_id} 已有关键词，请先删除或清空")

        # 复制关键词到目标商品ID
        copied_count = 0
        for keyword_data in source_keywords:
            keyword = keyword_data['keyword']
            reply = keyword_data['reply']
            keyword_type = keyword_data.get('type', 'text')
            
            if keyword_type == 'text':
                # 复制文本关键词
                success = db_manager.add_keyword(cid, keyword, reply, request.target_item_id)
                if success:
                    copied_count += 1
            elif keyword_type == 'image':
                # 复制图片关键词（需要复制图片文件）
                image_url = keyword_data.get('image_url')
                if image_url:
                    # 复制图片文件
                    new_image_url = image_manager.copy_image(image_url)
                    if new_image_url:
                        success = db_manager.save_image_keyword(cid, keyword, new_image_url, request.target_item_id)
                        if success:
                            copied_count += 1

        log_with_user('info', f"复制关键词成功: {cid}, 从商品 {request.source_item_id} 到 {request.target_item_id}, 共复制 {copied_count} 个关键词", current_user)

        return {
            "msg": "复制成功",
            "copied_count": copied_count,
            "source_item_id": request.source_item_id,
            "target_item_id": request.target_item_id
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"复制关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"复制关键词失败: {str(e)}")


# ================================
# 关键词库相关API
# ================================

class KeywordLibraryCreateRequest(BaseModel):
    name: str
    description: Optional[str] = None


class KeywordLibraryAddRequest(BaseModel):
    library_name: str
    keywords: List[Dict[str, Any]]

class KeywordLibraryApplyRequest(BaseModel):
    cookie_id: str
    item_id: str

class KeywordLibraryCrawlerRequest(BaseModel):
    sku_id: str
    mt_token: str


# ================================
# 通用词库相关模型
# ================================

class GlobalKeywordCreateRequest(BaseModel):
    keyword: str
    reply: str
    type: str = 'text'
    image_url: Optional[str] = None
    is_fuzzy: bool = False

class GlobalKeywordUpdateRequest(BaseModel):
    keyword: str
    reply: str
    type: str = 'text'
    image_url: Optional[str] = None
    is_fuzzy: bool = False

class GlobalKeywordBatchRequest(BaseModel):
    keywords: List[Dict[str, Any]]


class ItemExclusiveReplyRequest(BaseModel):
    reply_content: str
    enabled: bool = True


# ==================== 角色权限管理模型 ====================

class RoleCreateRequest(BaseModel):
    name: str
    description: str = ""

class RoleUpdateRequest(BaseModel):
    name: str = None
    description: str = None

class UserRoleUpdateRequest(BaseModel):
    role_ids: List[int]

class RolePermissionsUpdateRequest(BaseModel):
    permission_ids: List[int]

class RoleMenusUpdateRequest(BaseModel):
    menu_ids: List[int]


@app.get("/keyword-libraries")
def get_keyword_libraries(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取关键词库列表（全系统共享）"""
    try:
        user_id = current_user['user_id']
        logger.info(f"获取关键词库列表，用户ID: {user_id}")
        libraries = db_manager.get_keyword_libraries()  # 不传递user_id，获取所有词库
        logger.info(f"返回关键词库数量: {len(libraries)}")
        for lib in libraries:
            logger.info(f"库: {lib['name']}, 创建者: {lib.get('creator_name', '未知')}, 关键词数: {lib['keywords_count']}, 分享次数: {lib['share_count']}")
        return libraries
    except Exception as e:
        logger.error(f"获取关键词库列表失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取关键词库列表失败: {str(e)}")


@app.get("/keyword-libraries/{library_id}")
def get_keyword_library_detail(library_id: int, current_user: Dict[str, Any] = Depends(require_permission('keyword_library_manage'))):
    """获取关键词库详情"""
    try:
        # 验证词库是否存在（全系统共享，不需要检查用户权限）
        libraries = db_manager.get_keyword_libraries()
        library_exists = any(lib['id'] == library_id for lib in libraries)
        if not library_exists:
            raise HTTPException(status_code=404, detail="关键词库不存在")
        
        items = db_manager.get_keyword_library_items(library_id)
        return {
            "library_id": library_id,
            "items": items
        }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取关键词库详情失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取关键词库详情失败: {str(e)}")


@app.post("/keyword-libraries")
def create_keyword_library(request: KeywordLibraryCreateRequest, current_user: Dict[str, Any] = Depends(require_permission('keyword_library_manage'))):
    """创建关键词库"""
    try:
        user_id = current_user['user_id']
        library_id = db_manager.create_keyword_library(user_id, request.name, request.description)
        
        if library_id is None:
            raise HTTPException(status_code=500, detail="创建关键词库失败")
        
        log_with_user('info', f"创建关键词库成功: {request.name}", current_user)
        return {"msg": "创建成功", "library_id": library_id}
    except sqlite3.IntegrityError:
        raise HTTPException(status_code=400, detail="关键词库名称已存在")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"创建关键词库失败: {e}")
        raise HTTPException(status_code=500, detail=f"创建关键词库失败: {str(e)}")


@app.post("/keyword-libraries/add-keywords")
def add_keywords_to_library(request: KeywordLibraryAddRequest, current_user: Dict[str, Any] = Depends(get_current_user)):
    """向关键词库添加关键词"""
    try:
        user_id = current_user['user_id']
        
        # 查找或创建关键词库（全系统共享，但创建时归属当前用户）
        libraries = db_manager.get_keyword_libraries()
        library = next((lib for lib in libraries if lib['name'] == request.library_name), None)
        
        if not library:
            # 创建新的关键词库
            library_id = db_manager.create_keyword_library(user_id, request.library_name)
            if library_id is None:
                raise HTTPException(status_code=500, detail="创建关键词库失败")
        else:
            library_id = library['id']
        
        # 添加关键词到库
        success = db_manager.add_keywords_to_library(library_id, request.keywords)
        if not success:
            raise HTTPException(status_code=500, detail="添加关键词到库失败")
        
        log_with_user('info', f"向关键词库添加关键词成功: {request.library_name}, 数量: {len(request.keywords)}", current_user)
        return {"msg": "添加成功", "library_id": library_id}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"向关键词库添加关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"向关键词库添加关键词失败: {str(e)}")


@app.post("/keyword-libraries/{library_id}/apply")
def apply_keyword_library(library_id: int, request: KeywordLibraryApplyRequest, current_user: Dict[str, Any] = Depends(get_current_user)):
    """应用关键词库到指定账号的商品"""
    try:
        user_id = current_user['user_id']
        
        # 验证词库是否存在（全系统共享）
        libraries = db_manager.get_keyword_libraries()
        library_exists = any(lib['id'] == library_id for lib in libraries)
        if not library_exists:
            raise HTTPException(status_code=404, detail="关键词库不存在")
        
        # 验证账号权限
        cookie_details = db_manager.get_cookie_details(request.cookie_id)
        if not cookie_details or cookie_details['user_id'] != user_id:
            raise HTTPException(status_code=404, detail="账号不存在或无权限访问")
        
        # 获取关键词库内容
        library_items = db_manager.get_keyword_library_items(library_id)
        if not library_items:
            raise HTTPException(status_code=400, detail="关键词库为空")
        
        # 获取现有关键词
        existing_keywords = db_manager.get_keywords_with_type(request.cookie_id)
        
        # 合并关键词（避免重复）
        all_keywords = []
        existing_keys = {f"{kw['keyword']}|{kw.get('item_id', '')}" for kw in existing_keywords}
        
        for item in library_items:
            # 为关键词库中的关键词指定商品ID
            key = f"{item['keyword']}|{request.item_id}"
            if key not in existing_keys:
                all_keywords.append({
                    'keyword': item['keyword'],
                    'reply': item['reply'],
                    'item_id': request.item_id,
                    'type': item.get('type', 'text'),
                    'image_url': item.get('image_url')
                })
                existing_keys.add(key)
        
        if not all_keywords:
            raise HTTPException(status_code=400, detail="所有关键词已存在，无需添加")
        
        # 保存关键词（追加模式，不删除现有关键词），记录词库来源
        success = db_manager.add_keywords_append_with_library(request.cookie_id, [
            (kw['keyword'], kw['reply'], kw['item_id']) 
            for kw in all_keywords if kw.get('type', 'text') == 'text'
        ], library_id)
        
        if not success:
            raise HTTPException(status_code=500, detail="保存关键词失败")
        
        # 增加关键词库的分享次数
        db_manager.increment_library_share_count(library_id)
        
        log_with_user('info', f"应用关键词库成功: library_id={library_id}, cookie_id={request.cookie_id}, item_id={request.item_id}, 添加数量: {len(all_keywords)}", current_user)
        return {"msg": "应用成功", "added_count": len(all_keywords)}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"应用关键词库失败: {e}")
        raise HTTPException(status_code=500, detail=f"应用关键词库失败: {str(e)}")


@app.delete("/keyword-libraries/{library_id}")
def delete_keyword_library(library_id: int, current_user: Dict[str, Any] = Depends(require_permission('keyword_library_manage'))):
    """删除关键词库"""
    try:
        user_id = current_user['user_id']
        is_admin = current_user['username'] == 'admin'
        
        # 获取词库信息以检查创建者
        libraries = db_manager.get_keyword_libraries()
        target_library = next((lib for lib in libraries if lib['id'] == library_id), None)
        
        if not target_library:
            raise HTTPException(status_code=404, detail="关键词库不存在")
        
        # 检查删除权限：只有创建者或管理员可以删除
        if not is_admin and target_library['user_id'] != user_id:
            raise HTTPException(status_code=403, detail="只有创建者或管理员可以删除门店词库")
        
        # 删除词库（不传递user_id，因为权限已经检查过了）
        success = db_manager.delete_keyword_library(library_id)
        
        if not success:
            raise HTTPException(status_code=500, detail="删除关键词库失败")
        
        log_with_user('info', f"删除关键词库成功: library_id={library_id}", current_user)
        return {"msg": "删除成功"}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除关键词库失败: {e}")
        raise HTTPException(status_code=500, detail=f"删除关键词库失败: {str(e)}")


@app.post("/keyword-libraries/{library_id}/import-excel")
async def import_excel_to_library(
    library_id: int, 
    file: UploadFile = File(...),
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """从Excel文件导入关键词到门店词库（异步处理）"""
    try:
        user_id = current_user['user_id']
        
        # 验证门店词库权限
        library = db_manager.get_keyword_library_by_id(library_id, user_id)
        if not library:
            raise HTTPException(status_code=404, detail="关键词库不存在或无权限访问")
        
        # 检查文件类型
        if not file.filename.endswith(('.xlsx', '.xls')):
            raise HTTPException(status_code=400, detail="请上传Excel文件(.xlsx或.xls)")
        
        # 读取Excel文件内容
        file_content = await file.read()
        
        # 快速验证文件格式
        try:
            keyword_data_list = generate_keyword_data_from_excel(file_content, "")
            if not keyword_data_list:
                raise HTTPException(status_code=400, detail="Excel文件中没有有效的门店信息数据")
        except Exception as e:
            raise HTTPException(status_code=400, detail=f"Excel文件格式错误: {str(e)}")
        
        # 如果关键词数量较少，直接同步处理
        if len(keyword_data_list) <= 100:
            success = db_manager.add_keywords_to_library(library_id, keyword_data_list)
            if not success:
                raise HTTPException(status_code=500, detail="保存关键词到门店词库失败")
            
            log_with_user('info', f"Excel导入到门店词库成功: library_id={library_id}, 添加数量: {len(keyword_data_list)}", current_user)
            
            return {
                "msg": "导入成功",
                "added": len(keyword_data_list),
                "library_name": library['name'],
                "is_async": False
            }
        else:
            # 大量数据异步处理
            task_id = f"import_excel_{library_id}_{int(time.time())}"
            
            # 启动后台任务
            asyncio.create_task(process_excel_import_async(
                task_id, library_id, keyword_data_list, library['name'], current_user
            ))
            
            return {
                "msg": "开始异步处理",
                "task_id": task_id,
                "total_keywords": len(keyword_data_list),
                "library_name": library['name'],
                "is_async": True
            }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Excel导入到门店词库失败: {e}")
        raise HTTPException(status_code=500, detail=f"Excel导入失败: {str(e)}")


@app.post("/keyword-libraries/{library_id}/crawler-create")
async def crawler_create_library(
    library_id: int, 
    request: KeywordLibraryCrawlerRequest,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """使用爬虫抓取门店信息创建关键词库（异步处理）"""
    try:
        user_id = current_user['user_id']
        
        # 验证门店词库权限
        library = db_manager.get_keyword_library_by_id(library_id, user_id)
        if not library:
            raise HTTPException(status_code=404, detail="关键词库不存在或无权限访问")
        
        # 启动异步爬虫任务
        task_id = f"crawler_{library_id}_{int(time.time())}"
        
        # 创建后台任务
        asyncio.create_task(process_crawler_import_async(
            task_id, library_id, request.sku_id, request.mt_token, library['name'], current_user
        ))
        
        return {
            "success": True,
            "message": "开始异步抓取",
            "task_id": task_id,
            "library_name": library['name'],
            "is_async": True
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"爬虫创建门店词库失败: {e}")
        raise HTTPException(status_code=500, detail=f"爬虫抓取失败: {str(e)}")


@app.get("/keyword-libraries/task-status/{task_id}")
def get_task_status(task_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取异步任务状态"""
    if task_id not in task_status:
        raise HTTPException(status_code=404, detail="任务不存在")
    
    status = task_status[task_id].copy()
    
    # 自动清理超过1小时的任务状态
    current_time = time.time()
    if (status.get("completed_at", 0) > 0 and current_time - status["completed_at"] > 3600) or \
       (status.get("failed_at", 0) > 0 and current_time - status["failed_at"] > 3600):
        del task_status[task_id]
    
    return status


@app.get("/keyword-libraries/tasks")
def get_all_tasks(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户的所有任务状态"""
    user_tasks = {}
    current_time = time.time()
    
    for task_id, status in task_status.items():
        # 只返回未过期的任务
        if not ((status.get("completed_at", 0) > 0 and current_time - status["completed_at"] > 3600) or \
                (status.get("failed_at", 0) > 0 and current_time - status["failed_at"] > 3600)):
            user_tasks[task_id] = status
    
    return user_tasks


@app.post("/keyword-libraries/fix-stats")
def fix_keyword_library_stats(current_user: Dict[str, Any] = Depends(get_current_user)):
    """修复关键词库统计数据"""
    try:
        user_id = current_user['user_id']
        
        # 手动执行修复逻辑
        with db_manager.lock:
            cursor = db_manager.conn.cursor()
            
            # 更新所有关键词库的关键词数量
            cursor.execute("""
                UPDATE keyword_library 
                SET keywords_count = (
                    SELECT COUNT(*) 
                    FROM keyword_library_items 
                    WHERE keyword_library_items.library_id = keyword_library.id
                )
                WHERE user_id = %s
            """, (user_id,))
            
            # 确保share_count字段不为NULL
            cursor.execute("""
                UPDATE keyword_library 
                SET share_count = 0 
                WHERE user_id = %s AND share_count IS NULL
            """, (user_id,))
            
            db_manager.conn.commit()
        
        log_with_user('info', "关键词库统计数据修复完成", current_user)
        return {"msg": "统计数据修复成功"}
    except Exception as e:
        logger.error(f"修复关键词库统计数据失败: {e}")
        raise HTTPException(status_code=500, detail=f"修复统计数据失败: {str(e)}")


# ================================
# 通用词库管理 API
# ================================

@app.get("/global-keywords")
def get_global_keywords(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户的通用关键词"""
    try:
        user_id = current_user['user_id']
        keywords = db_manager.get_global_keywords(user_id)
        log_with_user('info', f"获取通用关键词列表，数量: {len(keywords)}", current_user)
        return keywords
    except Exception as e:
        logger.error(f"获取通用关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取通用关键词失败: {str(e)}")


@app.post("/global-keywords")
def create_global_keyword(request: GlobalKeywordCreateRequest, current_user: Dict[str, Any] = Depends(get_current_user)):
    """创建通用关键词"""
    try:
        # 自动检测是否为模糊匹配关键词
        from utils.message_utils import detect_fuzzy_keyword
        is_fuzzy = request.is_fuzzy or detect_fuzzy_keyword(request.keyword)
        
        user_id = current_user['user_id']
        success = db_manager.add_global_keyword(
            request.keyword,
            request.reply,
            request.type,
            request.image_url,
            True,  # enabled
            is_fuzzy,
            user_id
        )

        if success:
            log_with_user('info', f"创建通用关键词成功: {request.keyword}", current_user)
            return {"msg": "创建成功"}
        else:
            raise HTTPException(status_code=400, detail="关键词已存在")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"创建通用关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"创建通用关键词失败: {str(e)}")


@app.put("/global-keywords/{keyword_id}")
def update_global_keyword(keyword_id: int, request: GlobalKeywordUpdateRequest, current_user: Dict[str, Any] = Depends(get_current_user)):
    """更新通用关键词"""
    try:
        # 自动检测是否为模糊匹配关键词
        from utils.message_utils import detect_fuzzy_keyword
        is_fuzzy = request.is_fuzzy or detect_fuzzy_keyword(request.keyword)
        
        success = db_manager.update_global_keyword(
            keyword_id,
            request.keyword,
            request.reply,
            request.type,
            request.image_url,
            None,  # enabled (保持不变)
            is_fuzzy
        )

        if success:
            log_with_user('info', f"更新通用关键词成功: ID {keyword_id}", current_user)
            return {"msg": "更新成功"}
        else:
            raise HTTPException(status_code=400, detail="关键词重复或不存在")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"更新通用关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"更新通用关键词失败: {str(e)}")


@app.delete("/global-keywords/{keyword_id}")
def delete_global_keyword(keyword_id: int, current_user: Dict[str, Any] = Depends(get_current_user)):
    """删除通用关键词"""
    try:
        success = db_manager.delete_global_keyword(keyword_id)

        if success:
            log_with_user('info', f"删除通用关键词成功: ID {keyword_id}", current_user)
            return {"msg": "删除成功"}
        else:
            raise HTTPException(status_code=404, detail="关键词不存在")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除通用关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"删除通用关键词失败: {str(e)}")


@app.patch("/global-keywords/{keyword_id}/toggle")
def toggle_global_keyword_status(keyword_id: int, enabled: bool, current_user: Dict[str, Any] = Depends(get_current_user)):
    """切换通用关键词启用状态"""
    try:
        success = db_manager.toggle_global_keyword_status(keyword_id, enabled)

        if success:
            status_text = "启用" if enabled else "禁用"
            log_with_user('info', f"{status_text}通用关键词成功: ID {keyword_id}", current_user)
            return {"msg": f"{status_text}成功"}
        else:
            raise HTTPException(status_code=404, detail="关键词不存在")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"切换通用关键词状态失败: {e}")
        raise HTTPException(status_code=500, detail=f"切换状态失败: {str(e)}")


@app.post("/global-keywords/batch")
def batch_add_global_keywords(request: GlobalKeywordBatchRequest, current_user: Dict[str, Any] = Depends(get_current_user)):
    """批量添加通用关键词"""
    try:
        success_count = db_manager.batch_add_global_keywords(request.keywords)

        if success_count >= 0:  # 允许0个成功（全部重复的情况）
            log_with_user('info', f"批量添加通用关键词成功，数量: {success_count}", current_user)
            return {"msg": f"批量添加成功，共添加 {success_count} 个关键词"}
        else:
            raise HTTPException(status_code=500, detail="批量添加失败")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"批量添加通用关键词失败: {e}")
        raise HTTPException(status_code=500, detail=f"批量添加失败: {str(e)}")


# ================================
# 商品专属回复语管理 API
# ================================

@app.get("/item-exclusive-reply/{cookie_id}/{item_id}")
def get_item_exclusive_reply(cookie_id: str, item_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取商品专属回复语"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        result = db_manager.get_item_exclusive_reply(cookie_id, item_id)
        log_with_user('info', f"获取商品专属回复语: 账号={cookie_id}, 商品ID={item_id}", current_user)
        return result
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取商品专属回复语失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取专属回复语失败: {str(e)}")


@app.post("/item-exclusive-reply/{cookie_id}/{item_id}")
def save_item_exclusive_reply(cookie_id: str, item_id: str, request: ItemExclusiveReplyRequest, current_user: Dict[str, Any] = Depends(get_current_user)):
    """保存商品专属回复语"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        # 检查商品是否已配置关键词
        if not db_manager.has_item_keywords(cookie_id, item_id):
            raise HTTPException(status_code=400, detail="该商品未配置关键词，无法设置专属回复语")

        success = db_manager.save_item_exclusive_reply(cookie_id, item_id, request.reply_content, request.enabled)

        if success:
            log_with_user('info', f"保存商品专属回复语成功: 账号={cookie_id}, 商品ID={item_id}", current_user)
            return {"msg": "保存成功"}
        else:
            raise HTTPException(status_code=500, detail="保存失败")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"保存商品专属回复语失败: {e}")
        raise HTTPException(status_code=500, detail=f"保存专属回复语失败: {str(e)}")


@app.delete("/item-exclusive-reply/{cookie_id}/{item_id}")
def delete_item_exclusive_reply(cookie_id: str, item_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """删除商品专属回复语"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        success = db_manager.delete_item_exclusive_reply(cookie_id, item_id)

        if success:
            log_with_user('info', f"删除商品专属回复语成功: 账号={cookie_id}, 商品ID={item_id}", current_user)
            return {"msg": "删除成功"}
        else:
            raise HTTPException(status_code=500, detail="删除失败")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除商品专属回复语失败: {e}")
        raise HTTPException(status_code=500, detail=f"删除专属回复语失败: {str(e)}")


@app.get("/item-exclusive-replies/{cookie_id}")
def get_all_item_exclusive_replies(cookie_id: str, current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取指定账号的所有商品专属回复语"""
    try:
        # 检查cookie是否属于当前用户
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)

        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")

        result = db_manager.get_all_item_exclusive_replies(cookie_id)
        log_with_user('info', f"获取账号专属回复语列表: 账号={cookie_id}, 数量={len(result)}", current_user)
        return result
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取账号专属回复语列表失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取专属回复语列表失败: {str(e)}")


# 移除自动启动，由Start.py或手动启动
# if __name__ == "__main__":
#     uvicorn.run(app, host="0.0.0.0", port=8080)

@app.get("/keywords-paginated/{cid}")
def get_keywords_paginated(
    cid: str, 
    page: int = 1, 
    page_size: int = 50,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """分页获取关键词列表（优化大量关键词的加载性能）"""
    if cookie_manager.manager is None:
        raise HTTPException(status_code=500, detail="CookieManager 未就绪")

    # 检查cookie是否属于当前用户
    user_id = current_user['user_id']
    from db_manager import db_manager
    user_cookies = db_manager.get_all_cookies(user_id)

    if cid not in user_cookies:
        raise HTTPException(status_code=403, detail="无权限访问该Cookie")

    try:
        # 参数验证
        if page < 1:
            page = 1
        if page_size < 1 or page_size > 200:  # 限制最大页面大小
            page_size = 50

        # 使用分页查询
        result = db_manager.get_keywords_with_pagination(cid, page, page_size)
        
        return {
            "success": True,
            "data": result
        }
        
    except Exception as e:
        logger.error(f"分页获取关键词失败: {e}")
        raise HTTPException(status_code=500, detail="获取关键词失败")

@app.get("/dashboard/stats")
@cache_result(ttl=180, key_prefix="dashboard_stats")  # 缓存3分钟
async def get_dashboard_stats(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取仪表盘统计数据（优化版本）"""
    try:
        user_id = current_user['user_id']
        from db_manager import db_manager
        
        # 异步获取统计数据
        stats = await asyncio.get_event_loop().run_in_executor(
            thread_pool, 
            db_manager.get_account_summary_stats, 
            user_id
        )
        
        return {
            "success": True,
            "data": stats
        }
        
    except Exception as e:
        logger.error(f"获取仪表盘统计数据失败: {e}")
        return {
            "success": False,
            "message": "获取统计数据失败",
            "data": {
                'total_accounts': 0,
                'enabled_accounts': 0,
                'active_accounts': 0,
                'total_keywords': 0,
                'text_keywords': 0,
                'image_keywords': 0
            }
        }

# ==================== 订单管理API ====================

@app.get("/api/orders")
async def get_orders(
    page: int = 1,
    page_size: int = 20,
    cookie_id: Optional[str] = None,
    search: Optional[str] = None,
    search_type: Optional[str] = None,
    status: Optional[str] = None,
    current_user: dict = Depends(get_current_user)
):
    """获取订单列表"""
    try:
        # 如果不是管理员，只能查看自己的订单
        if not current_user.get('is_admin') and cookie_id:
            # 检查cookie是否属于当前用户
            cookie_details = db_manager.get_cookie_details(cookie_id)
            if not cookie_details or cookie_details.get('user_id') != current_user['id']:
                raise HTTPException(status_code=403, detail="无权限访问此账号的订单")
        
        # 获取用户的cookie列表（用于权限控制）
        user_cookies = db_manager.get_all_cookies(current_user['id'] if not current_user.get('is_admin') else None)
        
        # 如果指定了cookie_id但不在用户权限范围内，返回空结果
        if cookie_id and cookie_id not in user_cookies and not current_user.get('is_admin'):
            return {
                "success": True,
                "data": {
                    "orders": [],
                    "pagination": {
                        "current_page": page,
                        "page_size": page_size,
                        "total_count": 0,
                        "total_pages": 0,
                        "has_next": False,
                        "has_prev": False
                    }
                }
            }
        
        # 获取订单数据
        result = db_manager.get_orders(
            cookie_id=cookie_id,
            page=page,
            page_size=page_size,
            search_query=search,
            search_type=search_type,
            status_filter=status
        )
        
        # 构建分页信息
        pagination = {
            'current_page': result['current_page'],
            'page_size': result['page_size'],
            'total_count': result['total_count'],
            'total_pages': result['total_pages'],
            'has_next': result['current_page'] < result['total_pages'],
            'has_prev': result['current_page'] > 1
        }
        
        # 如果不是管理员，过滤掉不属于当前用户的订单
        if not current_user.get('is_admin'):
            filtered_orders = []
            for order in result['orders']:
                if order['cookie_id'] in user_cookies:
                    filtered_orders.append(order)
            
            # 重新计算分页信息
            pagination['total_count'] = len(filtered_orders)
            pagination['total_pages'] = (len(filtered_orders) + page_size - 1) // page_size
            result['orders'] = filtered_orders
        
        # 重新构建结果
        result = {
            'orders': result['orders'],
            'pagination': pagination
        }
        
        return {
            "success": True,
            "data": result
        }
    except Exception as e:
        logger.error(f"获取订单列表失败: {e}")
        return {
            "success": False,
            "message": f"获取订单列表失败: {str(e)}"
        }

@app.get("/api/orders/statistics")
async def get_order_statistics(
    cookie_id: Optional[str] = None,
    current_user: dict = Depends(get_current_user)
):
    """获取订单统计信息"""
    try:
        # 检查权限
        if cookie_id and not current_user.get('is_admin'):
            cookie_details = db_manager.get_cookie_details(cookie_id)
            if not cookie_details or cookie_details.get('user_id') != current_user['id']:
                raise HTTPException(status_code=403, detail="无权限访问此账号的统计")
        
        # 如果不是管理员且没有指定cookie_id，获取用户所有账号的统计
        if not current_user.get('is_admin') and not cookie_id:
            user_cookies = db_manager.get_all_cookies(current_user['id'])
            if not user_cookies:
                return {
                    "success": True,
                    "data": {
                        'total_orders': 0,
                        'status_counts': {},
                        'today_orders': 0,
                        'month_amount': 0
                    }
                }
            # 获取用户所有账号的统计（这里简化处理，实际可以聚合多个账号）
            cookie_id = list(user_cookies.keys())[0]  # 暂时只取第一个账号
        
        stats = db_manager.get_order_statistics(cookie_id)
        return {
            "success": True,
            "data": stats
        }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取订单统计失败: {e}")
        return {
            "success": False,
            "message": f"获取订单统计失败: {str(e)}"
        }

@app.get("/api/orders/{order_id}")
async def get_order_detail(
    order_id: str,
    cookie_id: Optional[str] = None,
    current_user: dict = Depends(get_current_user)
):
    """获取订单详情"""
    try:
        order = db_manager.get_order_by_id(order_id, cookie_id)
        if not order:
            raise HTTPException(status_code=404, detail="订单不存在")
        
        # 检查权限
        if not current_user.get('is_admin'):
            cookie_details = db_manager.get_cookie_details(order['cookie_id'])
            if not cookie_details or cookie_details.get('user_id') != current_user['id']:
                raise HTTPException(status_code=403, detail="无权限访问此订单")
        
        return {
            "success": True,
            "data": order
        }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取订单详情失败: {e}")
        return {
            "success": False,
            "message": f"获取订单详情失败: {str(e)}"
        }

class OrderCreateRequest(BaseModel):
    cookie_id: str
    order_id: str
    buyer_id: str
    item_id: Optional[str] = None
    item_title: Optional[str] = None
    order_status: str
    order_amount: Optional[float] = None
    buyer_message: Optional[str] = None
    seller_message: Optional[str] = None
    shipping_info: Optional[str] = None
    payment_time: Optional[str] = None
    shipping_time: Optional[str] = None
    delivery_time: Optional[str] = None
    refund_time: Optional[str] = None

@app.post("/api/orders")
async def create_order(
    request: OrderCreateRequest,
    current_user: dict = Depends(get_current_user)
):
    """创建订单"""
    try:
        # 检查权限
        if not current_user.get('is_admin'):
            cookie_details = db_manager.get_cookie_details(request.cookie_id)
            if not cookie_details or cookie_details.get('user_id') != current_user['id']:
                raise HTTPException(status_code=403, detail="无权限为此账号创建订单")
        
        # 检查订单是否已存在
        existing_order = db_manager.get_order_by_id(request.order_id, request.cookie_id)
        if existing_order:
            return {
                "success": False,
                "message": "订单已存在"
            }
        
        # 创建订单数据
        order_data = {
            'order_id': request.order_id,
            'buyer_id': request.buyer_id,
            'item_id': request.item_id,
            'item_title': request.item_title,
            'order_status': request.order_status,
            'order_amount': request.order_amount,
            'buyer_message': request.buyer_message,
            'seller_message': request.seller_message,
            'shipping_info': request.shipping_info,
            'payment_time': request.payment_time,
            'shipping_time': request.shipping_time,
            'delivery_time': request.delivery_time,
            'refund_time': request.refund_time
        }
        
        success = db_manager.save_order(request.cookie_id, order_data)
        if success:
            return {
                "success": True,
                "message": "订单创建成功"
            }
        else:
            return {
                "success": False,
                "message": "订单创建失败"
            }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"创建订单失败: {e}")
        return {
            "success": False,
            "message": f"创建订单失败: {str(e)}"
        }

class OrderUpdateRequest(BaseModel):
    buyer_id: Optional[str] = None
    item_id: Optional[str] = None
    item_title: Optional[str] = None
    order_status: Optional[str] = None
    order_amount: Optional[float] = None
    buyer_message: Optional[str] = None
    seller_message: Optional[str] = None
    shipping_info: Optional[str] = None
    payment_time: Optional[str] = None
    shipping_time: Optional[str] = None
    delivery_time: Optional[str] = None
    refund_time: Optional[str] = None

@app.put("/api/orders/{order_id}")
async def update_order(
    order_id: str,
    request: OrderUpdateRequest,
    cookie_id: Optional[str] = None,
    current_user: dict = Depends(get_current_user)
):
    """更新订单"""
    try:
        # 获取现有订单
        existing_order = db_manager.get_order_by_id(order_id, cookie_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="订单不存在")
        
        # 检查权限
        if not current_user.get('is_admin'):
            cookie_details = db_manager.get_cookie_details(existing_order['cookie_id'])
            if not cookie_details or cookie_details.get('user_id') != current_user['id']:
                raise HTTPException(status_code=403, detail="无权限修改此订单")
        
        # 更新订单数据
        order_data = existing_order.copy()
        
        # 只更新提供的字段
        for field, value in request.dict(exclude_unset=True).items():
            if value is not None:
                order_data[field] = value
        
        success = db_manager.save_order(existing_order['cookie_id'], order_data)
        if success:
            return {
                "success": True,
                "message": "订单更新成功"
            }
        else:
            return {
                "success": False,
                "message": "订单更新失败"
            }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"更新订单失败: {e}")
        return {
            "success": False,
            "message": f"更新订单失败: {str(e)}"
        }

@app.delete("/api/orders/{order_id}")
async def delete_order(
    order_id: str,
    cookie_id: str,
    current_user: dict = Depends(get_current_user)
):
    """删除订单"""
    try:
        # 获取订单信息用于权限检查
        existing_order = db_manager.get_order_by_id(order_id, cookie_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="订单不存在")
        
        # 检查权限
        if not current_user.get('is_admin'):
            cookie_details = db_manager.get_cookie_details(cookie_id)
            if not cookie_details or cookie_details.get('user_id') != current_user['id']:
                raise HTTPException(status_code=403, detail="无权限删除此订单")
        
        success = db_manager.delete_order(order_id, cookie_id)
        if success:
            return {
                "success": True,
                "message": "订单删除成功"
            }
        else:
            return {
                "success": False,
                "message": "订单删除失败"
            }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除订单失败: {e}")
        return {
            "success": False,
            "message": f"删除订单失败: {str(e)}"
        }

@app.post("/api/orders/parse-message")
async def parse_order_message(
    request: dict,
    current_user: dict = Depends(get_current_user)
):
    """解析订单消息并自动创建/更新订单"""
    try:
        cookie_id = request.get('cookie_id')
        message_data = request.get('message_data')
        
        if not cookie_id or not message_data:
            return {
                "success": False,
                "message": "缺少必要参数"
            }
        
        # 检查权限
        if not current_user.get('is_admin'):
            cookie_details = db_manager.get_cookie_details(cookie_id)
            if not cookie_details or cookie_details.get('user_id') != current_user['id']:
                raise HTTPException(status_code=403, detail="无权限处理此账号的消息")
        
        # 解析订单消息
        parsed_order = db_manager.parse_order_message(message_data)
        if not parsed_order:
            return {
                "success": False,
                "message": "无法从消息中解析出订单信息"
            }
        
        # 补充订单数据
        order_data = {
            'order_id': parsed_order.get('order_id'),
            'buyer_id': message_data.get('1', {}).get('1', {}).get('1', '').replace('@goofish', ''),
            'item_id': None,  # 从消息中提取商品ID（如果有的话）
            'item_title': None,  # 可以从商品管理中查找
            'order_status': parsed_order.get('order_status'),
            'order_amount': None,  # 消息中通常不包含金额
            'buyer_message': parsed_order.get('buyer_message'),
            'seller_message': None,
            'shipping_info': None,
            'payment_time': None,
            'shipping_time': None,
            'delivery_time': None,
            'refund_time': None,
            'raw_message': parsed_order.get('raw_message')
        }
        
        # 根据订单状态设置时间
        current_time = datetime.now().isoformat()
        if order_data['order_status'] == '待发货':
            order_data['payment_time'] = current_time
        elif order_data['order_status'] == '已发货':
            order_data['shipping_time'] = current_time
        elif order_data['order_status'] == '已退款':
            order_data['refund_time'] = current_time
        
        # 保存订单
        success = db_manager.save_order(cookie_id, order_data)
        if success:
            return {
                "success": True,
                "message": "订单信息已更新",
                "data": {
                    "order_id": order_data['order_id'],
                    "order_status": order_data['order_status']
                }
            }
        else:
            return {
                "success": False,
                "message": "保存订单信息失败"
            }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"解析订单消息失败: {e}")
        return {
            "success": False,
            "message": f"解析订单消息失败: {str(e)}"
        }


# ==================== 角色权限管理接口 ====================

@app.get('/admin/roles')
def get_all_roles(admin_user: Dict[str, Any] = Depends(require_admin)):
    """获取所有角色（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', "查询所有角色", admin_user)
        roles = db_manager.get_all_roles()
        
        # 为每个角色添加统计信息
        for role in roles:
            # 统计角色的用户数量
            cursor = db_manager.get_connection().cursor()
            cursor.execute('SELECT COUNT(*) FROM user_roles WHERE role_id = %s', (role['id'],))
            role['user_count'] = cursor.fetchone()[0]
            
            # 获取角色权限数量
            permissions = db_manager.get_role_permissions(role['id'])
            role['permission_count'] = len(permissions)
            
            # 获取角色菜单数量
            menus = db_manager.get_role_menus(role['id'])
            role['menu_count'] = len(menus)
        
        return {"roles": roles}
    except Exception as e:
        log_with_user('error', f"获取角色列表失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/admin/roles/{role_id}')
def get_role_detail(role_id: int, admin_user: Dict[str, Any] = Depends(require_admin)):
    """获取角色详细信息（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', f"查询角色详情: {role_id}", admin_user)
        
        role = db_manager.get_role_by_id(role_id)
        if not role:
            raise HTTPException(status_code=404, detail="角色不存在")
        
        # 获取角色的权限
        permissions = db_manager.get_role_permissions(role_id)
        
        # 获取角色的菜单
        menus = db_manager.get_role_menus(role_id)
        
        return {
            "role": role,
            "permissions": permissions,
            "menus": menus
        }
    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"获取角色详情失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.put('/admin/roles/{role_id}/permissions')
def update_role_permissions(role_id: int, request: RolePermissionsUpdateRequest, admin_user: Dict[str, Any] = Depends(require_admin)):
    """更新角色权限（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', f"更新角色权限: role_id={role_id}, permissions={request.permission_ids}", admin_user)
        
        # 检查角色是否存在
        role = db_manager.get_role_by_id(role_id)
        if not role:
            raise HTTPException(status_code=404, detail="角色不存在")
        
        # 更新权限
        success = db_manager.update_role_permissions(role_id, request.permission_ids)
        if success:
            log_with_user('info', f"角色权限更新成功: {role['name']}", admin_user)
            return {"success": True, "message": "角色权限更新成功"}
        else:
            return {"success": False, "message": "角色权限更新失败"}
    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"更新角色权限失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.put('/admin/roles/{role_id}/menus')
def update_role_menus(role_id: int, request: RoleMenusUpdateRequest, admin_user: Dict[str, Any] = Depends(require_admin)):
    """更新角色菜单（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', f"更新角色菜单: role_id={role_id}, menus={request.menu_ids}", admin_user)
        
        # 检查角色是否存在
        role = db_manager.get_role_by_id(role_id)
        if not role:
            raise HTTPException(status_code=404, detail="角色不存在")
        
        # 更新菜单
        success = db_manager.update_role_menus(role_id, request.menu_ids)
        if success:
            log_with_user('info', f"角色菜单更新成功: {role['name']}", admin_user)
            return {"success": True, "message": "角色菜单更新成功"}
        else:
            return {"success": False, "message": "角色菜单更新失败"}
    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"更新角色菜单失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.put('/admin/users/{user_id}/roles')
def update_user_roles(user_id: int, request: UserRoleUpdateRequest, admin_user: Dict[str, Any] = Depends(require_admin)):
    """更新用户角色（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', f"更新用户角色: user_id={user_id}, roles={request.role_ids}", admin_user)
        
        # 检查用户是否存在
        user = db_manager.get_user_by_id(user_id)
        if not user:
            raise HTTPException(status_code=404, detail="用户不存在")
        
        # 删除现有角色
        cursor = db_manager.get_connection().cursor()
        cursor.execute('DELETE FROM user_roles WHERE user_id = %s', (user_id,))
        
        # 分配新角色
        for role_id in request.role_ids:
            db_manager.assign_role_to_user(user_id, role_id)
        
        log_with_user('info', f"用户角色更新成功: {user['username']}", admin_user)
        return {"success": True, "message": "用户角色更新成功"}
    except HTTPException:
        raise
    except Exception as e:
        log_with_user('error', f"更新用户角色失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/admin/permissions')
def get_all_permissions(admin_user: Dict[str, Any] = Depends(require_admin)):
    """获取所有权限（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', "查询所有权限", admin_user)
        permissions = db_manager.get_all_permissions()
        return {"permissions": permissions}
    except Exception as e:
        log_with_user('error', f"获取权限列表失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/admin/menus')
def get_all_menus(admin_user: Dict[str, Any] = Depends(require_admin)):
    """获取所有菜单（管理员专用）"""
    from db_manager import db_manager
    try:
        log_with_user('info', "查询所有菜单", admin_user)
        menus = db_manager.get_all_menus()
        return {"menus": menus}
    except Exception as e:
        log_with_user('error', f"获取菜单列表失败: {str(e)}", admin_user)
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/user/permissions')
def get_user_permissions(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户权限"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        permissions = db_manager.get_user_permissions(user_id)
        return {"permissions": permissions}
    except Exception as e:
        logger.error(f"获取用户权限失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get('/user/menus')
def get_user_menus(current_user: Dict[str, Any] = Depends(get_current_user)):
    """获取当前用户可见菜单"""
    from db_manager import db_manager
    try:
        user_id = current_user['user_id']
        menus = db_manager.get_user_menus(user_id)
        return {"menus": menus}
    except Exception as e:
        logger.error(f"获取用户菜单失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


# ------------------------- 拉黑管理接口 -------------------------

@app.get("/api/blacklist/records")
async def get_blacklist_records(cookie_id: str = None, current_user: dict = Depends(get_current_user)):
    """获取拉黑记录列表"""
    try:
        # 如果指定了cookie_id，检查权限
        if cookie_id:
            user_id = current_user['user_id']
            user_cookies = db_manager.get_all_cookies(user_id)
            if cookie_id not in user_cookies:
                raise HTTPException(status_code=403, detail="无权限访问该Cookie")
        
        records = db_manager.get_blacklist_records(cookie_id)
        return {"code": 200, "data": records, "message": "获取成功"}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取拉黑记录失败: {e}")
        raise HTTPException(status_code=500, detail="获取失败")

@app.delete("/api/blacklist/records")
async def remove_blacklist_record(cookie_id: str, session_id: str, current_user: dict = Depends(get_current_user)):
    """移除拉黑记录"""
    try:
        # 检查权限
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)
        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限操作该Cookie")
        
        success = db_manager.remove_blacklist_record(cookie_id, session_id)
        if success:
            return {"code": 200, "message": "移除成功"}
        else:
            raise HTTPException(status_code=404, detail="未找到对应的拉黑记录")
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"移除拉黑记录失败: {e}")
        raise HTTPException(status_code=500, detail="移除失败")

@app.get("/api/blacklist/check")
async def check_blacklist_status(cookie_id: str, session_id: str, current_user: dict = Depends(get_current_user)):
    """检查用户是否已被拉黑"""
    try:
        # 检查权限
        user_id = current_user['user_id']
        user_cookies = db_manager.get_all_cookies(user_id)
        if cookie_id not in user_cookies:
            raise HTTPException(status_code=403, detail="无权限访问该Cookie")
        
        is_blacklisted = db_manager.is_user_blacklisted(cookie_id, session_id)
        return {"code": 200, "data": {"is_blacklisted": is_blacklisted}, "message": "检查完成"}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"检查拉黑状态失败: {e}")
        raise HTTPException(status_code=500, detail="检查失败")

